{"id":29182458,"url":"https://github.com/jxsl13/amqpx","last_synced_at":"2025-10-13T13:32:18.067Z","repository":{"id":61627569,"uuid":"541299486","full_name":"jxsl13/amqpx","owner":"jxsl13","description":"A robust amqp wrapper library for RabbitMQ's amqp091-go. Connection pooling, reconnect handling, batch processing and more.","archived":false,"fork":false,"pushed_at":"2025-05-13T13:59:08.000Z","size":789,"stargazers_count":18,"open_issues_count":12,"forks_count":3,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-07-01T20:05:57.625Z","etag":null,"topics":["amqp","amqp0-9-1","client","events","go","golang","rabbitmq","reconnect","resilience"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jxsl13.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-09-25T20:22:49.000Z","updated_at":"2025-05-13T13:58:20.000Z","dependencies_parsed_at":"2024-01-03T19:31:14.508Z","dependency_job_id":"d4f6ac43-beec-4849-b44b-dfdb640da10f","html_url":"https://github.com/jxsl13/amqpx","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/jxsl13/amqpx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxsl13%2Famqpx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxsl13%2Famqpx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxsl13%2Famqpx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxsl13%2Famqpx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jxsl13","download_url":"https://codeload.github.com/jxsl13/amqpx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jxsl13%2Famqpx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279015312,"owners_count":26085684,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-13T02:00:06.723Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amqp","amqp0-9-1","client","events","go","golang","rabbitmq","reconnect","resilience"],"created_at":"2025-07-01T20:05:59.430Z","updated_at":"2025-10-13T13:32:18.033Z","avatar_url":"https://github.com/jxsl13.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# amqpx\n\n[![GitHub license](https://badgen.net/github/license/jxsl13/amqpx)](https://pkg.go.dev/github.com/jxsl13/amqpx/blob/master/LICENSE)\n[![Go Reference](https://pkg.go.dev/badge/github.com/jxsl13/amqpx.svg)](https://pkg.go.dev/github.com/jxsl13/amqpx)\n[![Go Report Card](https://goreportcard.com/badge/github.com/jxsl13/amqpx)](https://goreportcard.com/report/github.com/jxsl13/amqpx)\n[![codecov](https://codecov.io/github/jxsl13/amqpx/branch/main/graph/badge.svg?token=bQuDbBFzMm)](https://codecov.io/github/jxsl13/amqpx)\n[![GitHub go.mod Go version of a Go module](https://img.shields.io/github/go-mod/go-version/jxsl13/amqpx.svg)](https://github.com/jxsl13/amqpx)\n[![GitHub latest release](https://badgen.net/github/tag/jxsl13/amqpx)](https://github.com/jxsl13/amqpx/tags)\n\n`amqpx` is a robust and easy to use wrapper for `github.com/rabbitmq/amqp091-go`.\n\n## Core features\n\n- connection \u0026 session (channel) pooling\n- reconnect handling\n- batch processing\n- pause/resume consumers\n- clean shutdown handling\n- sane defaults\n- resilience \u0026 robustness over performance by default (publisher \u0026 subscriber acks)\n- every default can be changed to your liking\n\nThis library is highly inspired by `https://github.com/houseofcat/turbocookedrabbit`\n\n## Requirements\n\n- Go 1.24 or higher\n- RabbitMQ 4.0 or higher for batch processing ordering guarantees ([Quorum Queues - Repeated Redeliveries](https://www.rabbitmq.com/docs/quorum-queues#repeated-requeues))\n\n## Getting started\n\n```shell\ngo get github.com/jxsl13/amqpx@latest\n```\n\n### Example\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"os/signal\"\n    \"syscall\"\n\n    \"github.com/jxsl13/amqpx\"\n    \"github.com/jxsl13/amqpx/logging\"\n    \"github.com/jxsl13/amqpx/pool\"\n    \"github.com/jxsl13/amqpx/types\"\n)\n\nfunc main() {\n    ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)\n    defer cancel()\n\n    amqpx.RegisterTopologyCreator(func(ctx context.Context, t *pool.Topologer) error {\n        // error handling omitted for brevity\n        _ = t.ExchangeDeclare(ctx, \"example-exchange\", \"topic\") // durable exchange by default\n        _, _ = t.QueueDeclare(ctx, \"example-queue\")             // durable quorum queue by default\n        _ = t.QueueBind(ctx, \"example-queue\", \"route.name.v1.event\", \"example-exchange\")\n        return nil\n    })\n    amqpx.RegisterTopologyDeleter(func(ctx context.Context, t *pool.Topologer) error {\n        // error handling omitted for brevity\n        _, _ = t.QueueDelete(ctx, \"example-queue\")\n        _ = t.ExchangeDelete(ctx, \"example-exchange\")\n        return nil\n    })\n\n    amqpx.RegisterHandler(\"example-queue\", func(ctx context.Context, msg types.Delivery) error {\n        fmt.Println(\"received message:\", string(msg.Body))\n        fmt.Println(\"canceling context\")\n        cancel()\n\n        // return error for nack + requeue\n        return nil\n    })\n\n    _ = amqpx.Start(\n        ctx,\n        amqpx.NewURL(\"localhost\", 5672, \"admin\", \"password\"), // or amqp://username@password:localhost:5672\n        amqpx.WithLogger(slog.New(slog.DiscardHandler)),      // provide a *slog.Logger\n    )\n    defer amqpx.Close()\n\n    _ = amqpx.Publish(ctx, \"example-exchange\", \"route.name.v1.event\", types.Publishing{\n        ContentType: \"application/json\",\n        Body:        []byte(\"my test event\"),\n    })\n\n    \u003c-ctx.Done()\n}\n\n```\n\n### Example with optional paramters\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n    \"os/signal\"\n    \"syscall\"\n\n    \"github.com/jxsl13/amqpx\"\n    \"github.com/jxsl13/amqpx/logging\"\n    \"github.com/jxsl13/amqpx/pool\"\n    \"github.com/jxsl13/amqpx/types\"\n)\n\nfunc SomeConsumer(cancel func()) pool.HandlerFunc {\n    return func(ctx context.Context, msg types.Delivery) error {\n        fmt.Println(\"received message:\", string(msg.Body))\n        fmt.Println(\"canceling context\")\n        cancel()\n\n        // return error for nack + requeue\n        return nil\n    }\n}\n\nfunc main() {\n    ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)\n    defer cancel()\n\n    amqpx.RegisterTopologyCreator(func(ctx context.Context, t *pool.Topologer) error {\n        // error handling omitted for brevity\n\n        _ = t.ExchangeDeclare(ctx, \"example-exchange\", \"topic\",\n            types.ExchangeDeclareOptions{\n                Durable: true,\n            },\n        )\n        _, _ = t.QueueDeclare(ctx, \"example-queue\",\n            types.QueueDeclareOptions{\n                Durable: true,\n                Args:    types.QuorumQueue,\n            },\n        )\n        t.QueueBind(ctx, \"example-queue\", \"route.name.v1.event\", \"example-exchange\")\n        return nil\n    })\n    amqpx.RegisterTopologyDeleter(func(ctx context.Context, t *pool.Topologer) error {\n        // error handling omitted for brevity\n        _, _ = t.QueueDelete(ctx, \"example-queue\")\n        _ = t.ExchangeDelete(ctx, \"example-exchange\")\n        return nil\n    })\n\n    amqpx.RegisterHandler(\"example-queue\",\n        SomeConsumer(cancel),\n        types.ConsumeOptions{\n            ConsumerTag: \"example-queue-cunsumer\",\n            Exclusive:   true,\n        },\n    )\n\n    _ = amqpx.Start(\n        ctx,\n        amqpx.NewURL(\"localhost\", 5672, \"admin\", \"password\"), // or amqp://username@password:localhost:5672\n        amqpx.WithLogger(slog.New(slog.DiscardHandler)),      // provide a *slog.Logger\n    )\n    defer amqpx.Close()\n\n    _ = amqpx.Publish(ctx, \"example-exchange\", \"route.name.v1.event\", types.Publishing{\n        ContentType: \"application/json\",\n        Body:        []byte(\"my test event\"),\n    })\n\n    \u003c-ctx.Done()\n}\n\n```\n\n## Types\n\nThe `amqpx` package provides a single type which incoorporates everything needed for consuming and publishing messages.\n\nThe `pool` package provides all of the implementation details .\n\n### `amqpx.AMQPX`\n\nThe `AMQPX` struct consists at least one connection pool, a `Publisher`, a `Subscriber` and a `Topologer`.\nUpon `Start(..)` and upon `Close()` a `Topologer` is created which creates the topology or destroys a topology based on one or *multiple* functions that were registered via `RegisterTopologyCreator` or `RegisterTopologyDeleter`.\nAfter the topology has been created, a `Publisher` is instantiated from a publisher connection and session `Pool`.\nThe `Publisher` can be used to publish messages to specific *exchanges* with a given *routing key*.\nIn case you register an event handler function via `RegisterHandler` or `RegisterBatchHandler`, then another connection and session `Pool` is created which is then used to instantiate a `Subscriber`. The `Subscriber` communicates via one or multiple separate TCP connections in order to prevent interference between the `Publisher` and `Subscriber` (tcp pushback).\n\nThe `amqpx` package defines a global variable that allows the package `amqpx` to be used like the `AMQPX` object.\n\n### `pool.Topologer`\n\nThe `Topologer` allows to create, delete, bind or unbind *exchanges* or *queues*\n\n### `pool.Publisher`\n\nThe `Publisher` allows to publish individual events or messages to *exchanges* with a given *routing key*.\n\n### `pool.Subscriber`\n\nThe `Subscriber` allows to register event handler functions that *consume messages from individual queues*.\nA `Subscriber` must be `Start()`ed in order for it to create consumer goroutines that process events from broker queues.\n\n## Development\n\nTests can all be run in parallel but the parallel testing is disabled for now because of the GitHub runners starting to behave weirdly when under such a load.\nThat is why those tests were disabled for the CI pipeline.\n\nTest flags you might want to add:\n\n```shell\ngo test -v -race -count=1 ./...\n```\n\n- see test logs\n- detect data races\n- do not cache test results\n\nStarting the tests:\n\n```shell\ngo test -v -race -count=1 ./...\n```\n\n### Test environment\n\n- Requires docker (and docker compose subcommand)\n\nStarting the test environment:\n\n```shell\nmake environment\n#or\ndocker compose up -d\n```\n\nThe test environment looks like this:\n\nWeb interfaces:\n\n- username: `admin` and password: `password`\n- [rabbitmq management interface: http://127.0.0.1:15672 -\u003e rabbitmq:15672](http://127.0.0.1:15672)\n- [out of memory rabbitmq management interface: http://127.0.0.1:25672 -\u003e rabbitmq-broken:15672](http://127.0.0.1:25672)\n\n```text\n127.0.0.1:5670     -\u003e rabbitmq-broken:5672     # out of memory rabbitmq\n127.0.0.1:5671     -\u003e rabbitmq:5672             # healthy rabbitmq connection which is never disconnected\n\n\n127.0.0.1:5672    -\u003e toxiproxy:5672    -\u003e rabbitmq:5672    # connection which is disconnected by toxiproxy\n127.0.0.1:5673    -\u003e toxiproxy:5673    -\u003e rabbitmq:5672    # connection which is disconnected by toxiproxy\n127.0.0.1:5674    -\u003e toxiproxy:5674    -\u003e rabbitmq:5672    # connection which is disconnected by toxiproxy\n...\n127.0.0.1:5771    -\u003e toxiproxy:5771    -\u003e rabbitmq:5672    # connection which is disconnected by toxiproxy\n\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjxsl13%2Famqpx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjxsl13%2Famqpx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjxsl13%2Famqpx/lists"}