# Service-to-Service Communication Patterns in the Macro Repository: HTTP, SQS, and Lambda

> Explore service-to-service communication patterns in the macro repository including synchronous HTTP APIs Axum asynchronous SQS and Lambda functions Learn how Macro Inc manages interservice communication efficiently

- Repository: [Macro/macro](https://github.com/macro-inc/macro)
- Tags: architecture
- Published: 2026-08-14

---

**The Macro codebase uses three primary service-to-service communication patterns: synchronous HTTP APIs built with Axum, asynchronous message passing via Amazon SQS, and AWS Lambda functions triggered by SQS or EventBridge events.**

This article examines how [macro-inc/macro](https://github.com/macro-inc/macro) implements inter-service communication across its Rust microservices architecture. Understanding these patterns provides insight into building scalable, decoupled systems that balance immediate response requirements with asynchronous processing needs.

## HTTP Communication with Axum

Macro uses **Axum** for synchronous, request/response communication between services. Each service exposing HTTP endpoints defines its router in a dedicated module, typically named `axum_router`, and mounts it in [`main.rs`](https://github.com/macro-inc/macro/blob/main/main.rs).

The router construction follows a consistent pattern. In [`services/unfurl_service/src/api/unfurl/mod.rs`](https://github.com/macro-inc/macro/blob/main/services/unfurl_service/src/api/unfurl/mod.rs), the service creates an `axum::Router` and registers route handlers:

```rust
use axum::{Router, routing::post};

pub fn unfurl_router() -> Router {
    Router::new()
        .route("/unfurl", post(unfurl_handler))
}

```

Similar patterns appear in [`services/static_file_service/src/api/mod.rs`](https://github.com/macro-inc/macro/blob/main/services/static_file_service/src/api/mod.rs) for file upload/download endpoints and [`services/notification_service/src/api/user_notification.rs`](https://github.com/macro-inc/macro/blob/main/services/notification_service/src/api/user_notification.rs) for notification CRUD operations. Each router is then served via `axum::serve` in the respective service's entry point.

## Asynchronous Messaging with SQS

For decoupled, event-driven communication, Macro relies on **Amazon SQS**. The pattern separates producers from consumers through typed queue wrappers.

### Publishing Events

Services create queue instances using `SqsQueue::new` or specialized wrappers like `SqsNotificationIngress`. The generic implementation in [`crates/webhook/src/outbound/sqs_queue.rs`](https://github.com/macro-inc/macro/blob/main/crates/webhook/src/outbound/sqs_queue.rs) provides the foundation for SQS producers across the codebase.

In [`services/notification_service/src/main.rs`](https://github.com/macro-inc/macro/blob/main/services/notification_service/src/main.rs), the service initializes its queue and publishes events:

```rust
use notification::outbound::queue::SqsQueue;

let notification_queue = SqsQueue::new(sqs_client.clone(), "notification-queue");
notification_queue.send_message(payload).await?;

```

Error handling is explicit: [`services/email_service/src/pubsub/util.rs`](https://github.com/macro-inc/macro/blob/main/services/email_service/src/pubsub/util.rs) records `FailureReason::SqsEnqueueFailed` when message enqueueing fails, enabling proper observability and retry logic.

### Consuming Messages

Consumers implement polling logic through `SqsQueue` or process messages in Lambda functions (covered in the next section). This separation allows scaling producers and consumers independently based on workload characteristics.

## Serverless Event Processing with AWS Lambda

Several Macro services run as **AWS Lambda functions**, triggered by SQS or EventBridge events. This pattern enables cost-effective, scalable processing of asynchronous workloads without maintaining persistent infrastructure.

### SQS-Triggered Lambda

The entry point in [`services/upload_extractor_lambda_handler/src/main.rs`](https://github.com/macro-inc/macro/blob/main/services/upload_extractor_lambda_handler/src/main.rs) demonstrates the standard pattern:

```rust
use aws_lambda_events::event::sqs::SqsEvent;
use lambda_runtime::{service_fn, LambdaEvent};

async fn handler(event: LambdaEvent<SqsEvent>) -> Result<(), anyhow::Error> {
    // decode the SQS record and process
}
let func = service_fn(handler);

```

The `LambdaEvent<SqsEvent>` wrapper provides structured access to queue messages with AWS Lambda's execution context.

### Multi-Event Lambda Handlers

[`services/document_text_extractor/src/handler/mod.rs`](https://github.com/macro-inc/macro/blob/main/services/document_text_extractor/src/handler/mod.rs) shows a more flexible approach using an `IncomingEvent` enum that matches on both `SqsEvent` and `EventBridgeEvent`:

```rust
match incoming_event {
    IncomingEvent::SqsEvent(sqs_event) => process_sqs(sqs_event).await,
    IncomingEvent::EventBridge(eventbridge_event) => process_eventbridge(eventbridge_event).await,
}

```

[`services/organization_retention_handler/src/main.rs`](https://github.com/macro-inc/macro/blob/main/services/organization_retention_handler/src/main.rs) follows the same SQS-triggered pattern for data lifecycle operations.

## Pattern Selection in Practice

| Pattern | Use Case | Implementation Location |
|---------|----------|------------------------|
| **Axum HTTP** | Synchronous API requests, real-time responses | `services/*/src/api/*/mod.rs` |
| **SQS Queues** | Reliable asynchronous messaging, work decoupling | [`crates/webhook/src/outbound/sqs_queue.rs`](https://github.com/macro-inc/macro/blob/main/crates/webhook/src/outbound/sqs_queue.rs) |
| **Lambda + SQS** | Scalable, event-driven processing, cost optimization | `services/*_lambda_handler/src/main.rs` |

The architectural choice depends on latency requirements, scaling needs, and operational complexity. HTTP serves immediate client requests, SQS enables reliable pipeline construction, and Lambda provides serverless elasticity for bursty or intermittent workloads.

## Summary

- **HTTP with Axum** provides synchronous service-to-service communication through REST endpoints defined in router modules and served via `axum::serve`.
- **SQS queues** enable asynchronous, decoupled messaging with explicit error handling through typed queue wrappers like `SqsQueue`.
- **AWS Lambda functions** process events serverlessly, triggered by SQS or EventBridge events using `LambdaEvent<T>` handlers.
- The codebase locates routing logic in `api/` modules, queue implementations in shared crates, and Lambda entry points in dedicated `*_lambda_handler` services.

## Frequently Asked Questions

### How does Macro handle HTTP request routing between services?

Each service defines its Axum router in an `api` module (commonly `axum_router`), composes routes with `Router::new().route()`, then mounts and serves the router in [`main.rs`](https://github.com/macro-inc/macro/blob/main/main.rs). This pattern appears in [`services/unfurl_service/src/api/unfurl/mod.rs`](https://github.com/macro-inc/macro/blob/main/services/unfurl_service/src/api/unfurl/mod.rs) and [`services/static_file_service/src/api/mod.rs`](https://github.com/macro-inc/macro/blob/main/services/static_file_service/src/api/mod.rs).

### What SQS implementation does Macro use for message queuing?

Macro implements a generic `SqsQueue` struct in [`crates/webhook/src/outbound/sqs_queue.rs`](https://github.com/macro-inc/macro/blob/main/crates/webhook/src/outbound/sqs_queue.rs) that wraps the AWS SDK. Services instantiate this with `SqsQueue::new(client, queue_name)` and call `send_message(payload).await` to publish events.

### When does Macro use Lambda instead of long-running services?

Lambda handles event-driven, bursty, or intermittent workloads—particularly SQS message processing and EventBridge-triggered operations. Services like `upload_extractor_lambda_handler` and `organization_retention_handler` use this pattern for cost-efficient scaling without persistent infrastructure.

### How are Lambda events structured in Macro's Rust code?

Handlers use `lambda_runtime::LambdaEvent<T>` where `T` is `SqsEvent` or `EventBridgeEvent` from `aws_lambda_events`. The `document_text_extractor` service demonstrates matching on an `IncomingEvent` enum to handle multiple trigger types in a single function.