--- title: "Cross-language: Python → Go over Redis" description: "A runnable demo — a Python service produces the canonical BabelQueue envelope and a Go service consumes it from the same Redis queue." source: https://babelqueue.com/docs/examples/1.x/cross-language-redis/ updated: 2026-06-07T00:00:00.000Z --- # Cross-language: Python → Go over Redis The whole point of BabelQueue: a message produced in **one** language is consumed natively in **another**, over the broker you already run, using one strict JSON envelope. This demo proves it end-to-end — a **Python** *or* **PHP** producer and a **Go** consumer sharing a Redis queue. The consumer never knows which language wrote the message; it only sees the canonical envelope and `meta.lang`. Every SDK uses the identical reliable-queue pattern (`RPUSH` to produce, `BLMOVE` to a `:processing` list to reserve, `LREM` to ack), so they interoperate on the plain `orders` Redis list. Full runnable sources: **[github.com/BabelQueue/babelqueue-examples](https://github.com/BabelQueue/babelqueue-examples)**. ## Producer — Python ```python # pip install "babelqueue[redis]" from babelqueue import BabelQueue app = BabelQueue("redis://localhost:6379/0", queue="orders") app.publish("urn:babel:orders:created", {"order_id": 1042, "amount": 99.90, "currency": "USD"}) app.publish("urn:babel:catalog:item.indexed", {"sku": "WIDGET-1", "title": "Café Widget ☕"}) ``` ## Producer — PHP (same queue, no framework) The framework-less core builds the envelope and the bundled `RedisTransport` does a plain `RPUSH` onto the identical `orders` list — so the Go consumer below reads PHP-produced messages without changing a line. ```php // composer require babelqueue/php-sdk predis/predis use BabelQueue\Codec\EnvelopeCodec; use BabelQueue\Transport\RedisTransport; $transport = new RedisTransport(new Predis\Client("redis://localhost:6379/0"), "orders"); $envelope = EnvelopeCodec::fromJob($job, "orders"); // $job: a PolyglotJob (URN + toPayload()) $transport->publish(EnvelopeCodec::encode($envelope), "orders"); ``` ## Consumer — Go ```go // go get github.com/babelqueue/babelqueue-go/redis import ( babelqueue "github.com/babelqueue/babelqueue-go" bqredis "github.com/babelqueue/babelqueue-go/redis" ) tr, _ := bqredis.New("redis://localhost:6379/0") app := babelqueue.NewApp(tr, babelqueue.WithDefaultQueue("orders")) app.Handle("urn:babel:orders:created", func(ctx context.Context, env babelqueue.Envelope) error { fmt.Printf("order %v (produced by %q)\n", env.Data["order_id"], env.Meta.Lang) return nil }) app.Consume(context.Background()) // routes by URN, forever ``` ## The proof Run either producer, then the Go consumer. The Go program prints messages it never produced — **`produced by "php"`** (or `"python"`) — with the data, `trace_id` and even unicode intact: ```text [go] order created id=1042 amount=99.9 USD trace=1d3b… (produced by "php") [go] order created id=1043 amount=12.5 EUR trace=79c3… (produced by "php") [go] item indexed sku=WIDGET-1 title="Café Widget ☕" (produced by "php") [go] processed 3 message(s) — same envelope, different language. ``` The envelope on the wire is the canonical shape every SDK emits: ```json { "job": "urn:babel:orders:created", "trace_id": "…", "data": { "order_id": 1042, "amount": 99.9, "currency": "USD" }, "meta": { "id": "…", "queue": "orders", "lang": "php", "schema_version": 1, "created_at": 1749132727000 }, "attempts": 0 } ``` ## Swap the ends The queue carries the canonical envelope, so any SDK can be on either side — a Go producer (`app.Publish(...)`) and a Python consumer (`@app.handler(...)` + `app.run()`) work the same way. PHP (framework-less `RedisTransport`, or Laravel/Symfony on a `babelqueue-*` connection), Node, Java and .NET read and write the identical envelope on their own transports.