All Products
Search
Document Center

Alibaba Cloud Service Mesh:Integrate message queues with swimlanes in permissive mode

Last Updated:Mar 11, 2026

Permissive mode swimlanes in Service Mesh (ASM) let you deploy partial environments that fall back to a baseline version for missing services. However, ASM cannot route message queue traffic through its mesh proxy the way it routes HTTP traffic. When a trace includes a message queue hop, the swimlane tag is lost unless your application explicitly preserves it.

The adaptation pattern described here keeps swimlane tags intact across message queue boundaries so that traffic continues to reach the correct swimlane after an asynchronous hop.

How it works

In a synchronous HTTP call chain, ASM automatically routes requests to the correct swimlane based on the x-asm-prefer-tag request header. Message queues break this chain because consumers pull messages independently -- the mesh proxy has no opportunity to inspect or route them.

To bridge this gap, your application must handle three responsibilities:

  1. Producer: write swimlane metadata into each message. Embed two pieces of information -- the swimlane the producer belongs to (used as a filter key) and the swimlane tag from the incoming request (used for downstream routing).

  2. Consumer: filter messages by swimlane. Subscribe only to messages whose filter key matches the consumer's own swimlane.

  3. Consumer: restore the swimlane tag on outgoing requests. After consuming a message, extract the swimlane tag from the message metadata and set it as the x-asm-prefer-tag header on downstream HTTP requests. This allows the mesh proxy to resume tag-based routing.

Prerequisites

Message queue requirements

The message queue must support:

  • Custom metadata on messages -- producers attach swimlane information to each message.

  • Consumer-side filtering -- consumers subscribe selectively based on a filter key (also known as a tag-filtering condition field) to receive only messages from their own swimlane.

Deployment constraints

In a pull-based message queue, the consumer cannot access service discovery information for the swimlane. This means you must deploy producers and consumers together -- deploy both in a swimlane, or neither.

SwimlaneProducerConsumerValid?
v1DeployedDeployedYes
v2DeployedDeployedYes
v2DeployedNot deployedNo
v2Not deployedDeployedNo
v2Not deployedNot deployedYes -- requests fall back to v1 in permissive mode
Application deployment patterns
Important

Deploying only a producer or only a consumer in a swimlane is an invalid deployment. Always deploy them as a pair, or omit both and let permissive mode route traffic to the baseline swimlane.

Step 1: Write swimlane tags to messages (producer)

When a producer (for example, APP-B) sends a message to the queue, it must include two metadata fields:

Metadata fieldSourcePurpose
Swimlane of the producer (filter key)Environment variable injected into the workloadAllows consumers to filter messages by swimlane
Swimlane tag from the incoming requestx-asm-prefer-tag request headerPreserves the original routing tag for downstream services
Producer writing swimlane tags to messages

Where each value comes from:

  • Swimlane of the producer -- Determined by the workload tag. Expose an environment variable (for example, ASM_SWIMLANE_TAG) in the pod spec so the application can read its swimlane assignment.

  • Swimlane tag from the incoming request -- After traffic passes through the ASM ingress gateway, ASM passes tags to end-to-end HTTPS through the x-asm-prefer-tag request header. Read this header from the inbound HTTP request and write its value into the message metadata.

Example: producer writes swimlane metadata

The following pseudocode shows how the producer reads the swimlane information and attaches it to the message:

import os
from flask import request

# Read the swimlane assignment from the environment variable
# that ASM injects into the workload pod.
producer_swimlane = os.environ.get("ASM_SWIMLANE_TAG", "default")

# Read the swimlane routing tag from the incoming HTTP request header.
routing_tag = request.headers.get("x-asm-prefer-tag", "")

# Attach both values to the message metadata before publishing.
message = {
    "body": payload,
    "metadata": {
        "filter_key": producer_swimlane,       # Consumer-side filtering
        "x-asm-prefer-tag": routing_tag         # Downstream routing
    }
}

mq_client.publish(topic="order-events", message=message)

Example message metadata:

Message metadata:
  filter_key:        "v1"              # Swimlane of the producer (APP-B is deployed in v1)
  x-asm-prefer-tag:  "v2"              # Swimlane tag from the original request
Message body:
  { ... actual payload ... }

Step 2: Filter messages by swimlane (consumer)

Each consumer subscribes to messages using the filter key that matches its own swimlane. This makes sure a consumer only processes messages from producers in the same swimlane.

Consumer filtering messages by swimlane

Example: consumer subscribes with a filter key

import os

consumer_swimlane = os.environ.get("ASM_SWIMLANE_TAG", "default")

# Subscribe only to messages whose filter_key matches this consumer's swimlane.
mq_client.subscribe(
    topic="order-events",
    filter_expression=f"filter_key = '{consumer_swimlane}'"
)

Scenario 1: Both producer and consumer deployed in each swimlane

When both swimlanes v1 and v2 have producers and consumers:

  • APP-C(v1) subscribes with filter key v1 and consumes only messages from APP-B(v1).

  • APP-C(v2) subscribes with filter key v2 and consumes only messages from APP-B(v2).

Traffic stays isolated within each swimlane.

Scenario 2: Neither producer nor consumer deployed in a swimlane

When swimlane v2 has only APP-A(v2) and APP-D(v2) -- no producer or consumer:

  1. APP-A(v2) sends a request. Because APP-B(v2) does not exist, permissive mode routes the request to APP-B(v1).

  2. APP-B(v1) writes the message to the queue with filter key v1. The x-asm-prefer-tag value in the message metadata remains v2 (the original request's swimlane tag).

  3. APP-C(v1) consumes the message (filter key matches v1).

  4. APP-C(v1) removes the swimlane v1 tag carried in the message and reads the x-asm-prefer-tag value (v2) from the message metadata, then sets it on the outgoing HTTP request.

  5. The mesh proxy routes the request to APP-D(v2) based on the x-asm-prefer-tag: v2 header.

This preserves end-to-end swimlane routing even though the message passed through the baseline swimlane.

Step 3: Restore the swimlane tag on downstream requests (consumer)

After consuming a message, propagate the swimlane tag to all downstream HTTP requests. Without this step, the mesh proxy cannot route subsequent requests to the correct swimlane.

Consumer restoring swimlane tags on downstream requests

To propagate the tag:

  1. Extract the x-asm-prefer-tag value from the consumed message's metadata.

  2. Set the x-asm-prefer-tag header on all outgoing HTTP requests to downstream services.

The mesh proxy then routes these requests to the swimlane specified by the header value.

Example: consumer restores the swimlane tag

import requests

def on_message(message):
    # Extract the swimlane routing tag from the consumed message.
    routing_tag = message.metadata.get("x-asm-prefer-tag", "")

    # Set the tag as a request header on all downstream HTTP calls.
    headers = {"x-asm-prefer-tag": routing_tag}

    response = requests.post(
        "http://app-d:8080/process",
        json=message.body,
        headers=headers
    )

Quick reference: fields to set and propagate

FieldWhere to setValue sourcePurpose
Message filter keyMessage metadata (producer)Workload environment variable (ASM_SWIMLANE_TAG)Consumer-side message filtering
x-asm-prefer-tagMessage metadata (producer)Inbound HTTP request headerPreserves the swimlane routing tag across the message queue hop
x-asm-prefer-tagOutbound HTTP request header (consumer)Consumed message metadataRestores tag-based routing for downstream services