An AMQP 0-9-1 Go client maintained by the RabbitMQ team. Originally by @streadway: `streadway/amqp`
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
Bump CI windows workflow RabbitMQ and Erlang versions Currently, windows workflow versions are: RabbitMQ: 3.13.4 Erlang: 26.2.5.1 Bumping to: RabbitMQ: 4.3.0 Erlang: 27.3.4.11 | 3 个月前 | |
chore(deps): reduce github-actions dependabot updates to weekly Daily checks were producing frequent low-value bumps (e.g. codeql-action patch releases); weekly cuts noise while still catching updates. | 23 天前 | |
Feature: implement automatic connection and channel recovery with state change notifications (#339) * feat: implement automatic connection and channel recovery Add built-in support for automatically recovering dropped connections and channels without requiring application-level reconnect loops. Key changes: - Add Recovery configuration struct to enable and configure auto-reconnect behavior (max retries, intervals). - Implement Connection.Reconnect() to automatically re-dial the server, perform TLS handshakes, and restore the underlying connection state. - Implement Channel.Reconnect() to seamlessly reopen channels, re-enable publisher confirms, and automatically re-issue active consumers using the new consumerConfig state tracking. - Add DefaultConnectionRecovery to monitor NotifyClose events in the background and trigger the reconnect sequence on unexpected closures. - Add _examples/recovery/recovery.go to demonstrate the new recovery capabilities. Note: TopologyRecovery (automatic re-declaration of queues, exchanges, and bindings) will be implemented through a follow-up change. * feat: add state change notifications for connection and channel Introduces `NotifyStateChange` to both `Connection` and `Channel`, allowing applications to monitor and react to lifecycle state transitions (open, reconnecting, closing, closed). Changes included: - Added `lifecycle.go` to manage state transitions and broadcast events. - Instrumented `Connection` and `Channel` to emit state changes during dialing, closing, shutdown, and automatic recovery. - Updated `_examples/recovery/recovery.go` to demonstrate how to use `NotifyStateChange` to block application publishers while the underlying connection is reconnecting. * Add connection and channel recovery integration tests * feat: add support for conditional connection and channel recovery - Introduce a configurable list of recoverable exception codes (`RecoverableExceptionsCodes`) in `ReconnectionConfig` to dynamically determine whether recovery should be triggered. - DefaultConnectionRecovery will attempt connection and channel recovery when error encountered is `320 CONNECTION_FORCED` or `541 INTERNAL_ERROR` - Expose Public methods for consumer applications to configure/extend list of error codes that should recover connection and channel. - refactor recovery-specific structs and logic into a new dedicated `recovery.go` file to simplify `connection.go`. - Add the `TestConnectionRecoveryNonRecoverableChannelClose` integration test in `recovery_test.go` with a reusable `waitForChannelClose` helper to verify that soft exceptions (like `406 PRECONDITION_FAILED` and `405 RESOURCE_LOCKED`) close the channels, do not trigger automatic recovery, and leave the parent connection open. * Close channel when confirmSelect or basicConsume fails in the recovery loop * Fix AI Review: RecoverableErrorCodes related data race and shared reference * Fix AI review: reserve existing open channel IDs in new allocator during reconnection * Fix AI review: implement bounded concurrent state change listener framework Refactor the connection and channel state change notification mechanism in `LifeCycle` to resolve goroutine leaks, unbounded memory growth, and single-listener limitations. - Support multiple concurrent state change listeners via a slice of `stateListener`s instead of a single replaced channel. - Isolate listeners so that a slow or blocked listener does not block other listeners or the main `SetState()` execution. - Implement a sliding-window bounded queue (max size 50) per listener to prevent unbounded memory growth if a listener stops reading. - Guarantee strict FIFO ordering of state transitions per listener by spawning at most one dedicated delivery goroutine (`deliverToListener`) per listener. - Cleanly and automatically close listener channels when the terminal `StateClosed` transition is successfully sent, preventing user-side goroutine hangs. - Add an integration test to verify listener recovery and clean close on channel/connection closure. * Fix AI review: add closeRecovery and NotifyRecoveryCancel to support interruptible reconnection * refactor: simplify connection and channel lifecycle state management - Introduced `LifeCycleState` as a custom `byte` type with iota constants: `StateOpen`, `StateReconnecting`, `StateClosing`, and `StateClosed`. - Updated `StateChanged` to include an `Err` field to carry terminal errors associated with `StateClosed` directly in the dispatched event. - Making `lifeCycle` and `newLifeCycle` private. * Fix memory leak in internal lifecycle * Remove DialRecovery function from connection.go Removes the `DialRecovery` function from connection.go. All auto-recovery configuration should be passed via `DialConfig(url, Config{Recovery: ...})` . * Add "Experimental" comment for Recovery feature Also, add comment for NotifyStateChange so that consumer must consume from channel returned by NotifyStateChange so that it doesn't block internal goroutine and cause leaks. --------- Co-authored-by: Aitor Perez <1515757+Zerpet@users.noreply.github.com> | 2 个月前 | |
Disable keep-alives in integration HTTP test helper The management API helper `baseCall` used a zero-value `http.Client`, which relies on the shared default transport and pools idle keep-alive connections. An idle connection left over from the last admin call in a test outlives the test, and `goleak.VerifyTestMain` flags its `net/http` reader/writer goroutines at suite teardown. Give the client a dedicated transport with `DisableKeepAlives` set so each one-shot call closes its TCP connection when the response is read, leaving no pooled connection behind. | 1 个月前 | |
Make target to spin up RabbitMQ + TLS Signed-off-by: Aitor Pérez Cedres <acedres@vmware.com> | 3 年前 | |
run gofumpt -w . | 2 年前 | |
Update CONTRIBUTING.md and .gitignore files 1. Fix broken golangci download link and some typos in the CONTRIBUTING.md 2. Fix .gitignore to correctly ignore example binaries | 3 个月前 | |
fix: modernize lint issues | 5 个月前 | |
Release v1.14.0 - Bump buildVersion to "1.14.0" in connection.go - Update CHANGELOG.md with release notes for v1.14.0 | 12 天前 | |
docs: update CLAUDE.md with lifecycle/log files and updated recovery details Adds lifecycle.go and log.go to the architecture map, corrects a stale reference to a non-existent RecoverableErrorCodes field, documents TopologyRecoveryMode/OnTopologyEntityError, and clarifies the actual Connection teardown mutex order. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> | 24 天前 | |
Add code of conduct | 5 年前 | |
Update CONTRIBUTING.md and .gitignore files 1. Fix broken golangci download link and some typos in the CONTRIBUTING.md 2. Fix .gitignore to correctly ignore example binaries | 3 个月前 | |
Update Copyright Statement Hello team! I am helping update the Copyright Statement, please let me know if you have any questions! | 5 年前 | |
Fix inconsistencies in the Makefile 1. `CONTRIBUTING.md` refer make target `checks` but Makefile has `check` 2. Make all targets discoverable via `make list` 3. Use `rabbitmq:4-management` in the target `rabbitmq-server-tls` | 3 个月前 | |
doc: remove auto-reconnect from non-goals in README Remove the "Auto reconnect and re-synchronization of client and server topologies" section from the list of non-goals in README.md. This is no longer a non-goal because: - Automatic connection and channel recovery was recently implemented in #339. - Topology recovery is planned to be implemented soon as a follow-up. | 2 个月前 | |
Add a guide to release a new version [skip ci] Signed-off-by: Aitor Perez Cedres <acedres@vmware.com> | 3 年前 | |
perf: replace bytes.Buffer with strings.Builder in allocator.go for improved performance | 1 年前 | |
run gofumpt -w . | 2 年前 | |
fix: redact and zero out plaintext SASL credentials after handshake (#350) - Implement `fmt.Stringer` on `PlainAuth` and `AMQPlainAuth` to redact passwords from logs, reflection, or APM dumps. - Zero out credentials in `Connection.Config.SASL` after a successful handshake in `openComplete()`. - Extract SASL setup from connection URIs into a new helper method `Config.setSASL(uri URI)`. - Reset and reinitialize SASL credentials from the connection recovery URL (`c.url`) in `Reconnect()` to ensure automatic reconnection succeeds after the previous connection's credentials were zeroed out. - Add comprehensive unit tests in `auth_test.go` and `connection_unit_test.go` verifying redacting, zeroing, and recovery restoration of credentials. | 2 个月前 | |
fix: redact and zero out plaintext SASL credentials after handshake (#350) - Implement `fmt.Stringer` on `PlainAuth` and `AMQPlainAuth` to redact passwords from logs, reflection, or APM dumps. - Zero out credentials in `Connection.Config.SASL` after a successful handshake in `openComplete()`. - Extract SASL setup from connection URIs into a new helper method `Config.setSASL(uri URI)`. - Reset and reinitialize SASL credentials from the connection recovery URL (`c.url`) in `Reconnect()` to ensure automatic reconnection succeeds after the previous connection's credentials were zeroed out. - Add comprehensive unit tests in `auth_test.go` and `connection_unit_test.go` verifying redacting, zeroing, and recovery restoration of credentials. | 2 个月前 | |
Make target to spin up RabbitMQ + TLS Signed-off-by: Aitor Pérez Cedres <acedres@vmware.com> | 3 年前 | |
Fix linter warnings (#156) - Unreachable code - Variable names using snake_case instead of CamelCase - Unused parameters - Redundant parenthesis - Shell-bang was not set correctly Any code after `t.Fatalf` is not executed, because this function stops execution. Signed-off-by: Aitor Pérez Cedres <acedres@vmware.com> Signed-off-by: Aitor Pérez Cedres <acedres@vmware.com> Co-authored-by: Luke Bakken <luke@bakken.io> | 3 年前 | |
docs: warn Reconnect()/reconnectChannel() callers to coordinate via NotifyStateChange IsClosed() momentarily reports false as soon as the new socket/channel is swapped in, before the AMQP handshake actually completes. A call made unconditionally in that window can interleave a frame with the handshake and get rejected by the broker as a protocol violation. Document that applications should wait for StateOpen via NotifyStateChange before issuing new operations instead of calling into the Connection/Channel unconditionally during recovery. | 27 天前 | |
fix: add closeInit race fix to Channel.Close()/reconnectChannel() Channel.Close() never got the closeInit signal that Connection.Close() uses to stop a Reconnect() that hasn't started yet: it only called closeRecovery(), which cancels channels already registered, but reconnectChannel() doesn't register its cancel channel until after acquiring ch.reconnecting. If Close() ran first, the signal had nothing to cancel and was silently dropped, letting reconnectChannel() run its full retry loop with Close() blocked behind it for no reason. Add closeInit as an atomic.Bool on Channel. Close() sets it before racing for ch.reconnecting; reconnectChannel() checks it right after acquiring the lock and aborts with ErrClosed instead of proceeding. Also reset it in resetState() so a stale closeInit from a lost race doesn't permanently block recovery on a later, unrelated drop of the same channel. Add TestReconnectChannelAbortsWhenCloseWonTheRace, mirroring TestReconnectAbortsWhenCloseWonTheRace at the channel level. | 1 个月前 | |
fix: reject frames exceeding negotiated frame_max before allocation (#369) * fix: reject frames exceeding negotiated frame_max before allocation A malicious or compromised broker could declare an oversized length in a frame header (e.g. within a basic.deliver content body frame) and force the client to allocate memory for it, bypassing the frame_max negotiated during connection.tune and enabling a memory-exhaustion DoS. Track the negotiated frame_max in a new atomic Connection.maxFrameSize field, mirrored from Config.FrameSize once connection.tune completes, and check every incoming frame's declared size against it in reader.ReadFrame before dispatching to the type-specific parsers that allocate the payload buffer. Frames over the limit are rejected with ErrFrameTooLarge instead of being read. * refactor: avoid uint64 widening in frame_max size check Rewrite the oversized-frame check in reader.ReadFrame to compare directly in uint32 (size > max-frameHeaderSize) instead of widening both operands to uint64 (size+frameHeaderSize > max). This is safe from underflow only because maxFrameSize is always either 0 or negotiateFrameSize's frameMinSize floor (4096) or higher. Also add a regression test covering an explicitly unlimited (maxFrameSize == 0) negotiated frame_max with a large frame. | 1 个月前 | |
Use a single timer across all notifications. Avoids a channel leak and reduces footprint. [ai-assisted=yes] | 2 个月前 | |
Avoid notifications blocking reader. Add 5s timeout to notifications to avoid blocking reader when notification channel is full. [ai-assisted=yes] | 2 个月前 | |
Release v1.14.0 - Bump buildVersion to "1.14.0" in connection.go - Update CHANGELOG.md with release notes for v1.14.0 | 12 天前 | |
test: retry cleanup connection after clearing memory alarm The broker doesn't lift the memory alarm instantaneously after the watermark is reset, so integrationQueue could return a nil channel in the test cleanup, causing QueueDelete to panic on a nil pointer dereference instead of failing cleanly. Also close the dialed connection in integrationQueue when channel setup fails, so repeated retries don't leak sockets, and widen the retry interval to reduce connection churn against the broker. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> | 1 个月前 | |
Enforce frame size in pre-negotiation state As per AMQP 091 spec, before Tune frames are exchanged, the max frame size must be 4096 bytes. | 27 天前 | |
feat: forget auto-delete topology on last consumer/binding removal Auto-delete queues and exchanges that have lost all their consumers or bindings are deleted by the broker immediately; tracking them further produces a stale entry that resurrects them incorrectly on recovery. When topology recovery is enabled, auto-delete entities must be removed from the recovery store as soon as the condition that will trigger their broker-side deletion is met. This commit implements that logic and also adds integration tests to cover: - auto-delete queue forgotten only after the last consumer cancels (not on the first of two cancels) - auto-delete exchange cascade-forgotten after QueueUnbind - QueueDelete cascading to the source exchange - ExchangeUnbind cascading to the source exchange - full three-level chain (outerExchange→innerExchange→queue→consumer) where a single cancel cascades all three entities, verified both in the topology store and on the broker after connection recovery Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> | 1 个月前 | |
feature: implement automatic topology recovery - Define the `TopologyRecovery` interface and `DefaultTopologyRecovery` implementation to manage topology restoration. - Introduce `TopologyConfiguration` and associated configuration structs (`QosConfig`, `ExchangeConfig`, `QueueConfig`, `BindingConfig`, `ExchangeBindingConfig`) to track active topology state on each channel. - Automatically record QoS settings, exchange/queue declarations, and bindings on the channel when topology recovery is enabled. - Automatically remove recorded topology upon deletion or unbinding of exchanges and queues, performing in-place cleanup of related bindings to avoid extra allocations. - Re-declare and re-bind all tracked topology elements during channel setup (`setupChannel`) upon successful reconnection. - Handle server-generated queue name changes during recovery, automatically updating the internal queue registry, bindings, and active consumer configurations with the new server-assigned names. --- fix: prevent recovery failures on deleted queues and deduplicate bindings This change ensures that when a queue is deleted, its consumers are cleanly terminated and untracked. It also avoids accumulating duplicate binding configurations and adds unit & integration testing for deleted queue scenarios. | 1 个月前 | |
fix: expose delivery not initialized error This error can happen when a Delivery (message) is ack/nack/reject after the AMQP channel is closed, and the consuming function/routine does not check the status of Go receive operation. | 1 年前 | |
fix: expose delivery not initialized error This error can happen when a Delivery (message) is ack/nack/reject after the AMQP channel is closed, and the consuming function/routine does not check the status of Go receive operation. | 1 年前 | |
Un-deprecate non-context Publish functions (#259) The context was not honoured in any of the *WithContext functions. This is confusing, and arguably broken. However, we cannot immediately fix the context-support situation due to https://github.com/rabbitmq/amqp091-go/issues/124#issuecomment-1578529925 This commit undeprecates the non-context variants of publish, and documents that both variants are equivalent. The example now favours the non-context variants. Related to #195 Signed-off-by: Aitor Perez Cedres <aitor.perez@broadcom.com> | 2 年前 | |
run gofumpt -w . | 2 年前 | |
Add support for unsigned type values Fixes #302 | 5 个月前 | |
fix: reject frames exceeding negotiated frame_max before allocation (#369) * fix: reject frames exceeding negotiated frame_max before allocation A malicious or compromised broker could declare an oversized length in a frame header (e.g. within a basic.deliver content body frame) and force the client to allocate memory for it, bypassing the frame_max negotiated during connection.tune and enabling a memory-exhaustion DoS. Track the negotiated frame_max in a new atomic Connection.maxFrameSize field, mirrored from Config.FrameSize once connection.tune completes, and check every incoming frame's declared size against it in reader.ReadFrame before dispatching to the type-specific parsers that allocate the payload buffer. Frames over the limit are rejected with ErrFrameTooLarge instead of being read. * refactor: avoid uint64 widening in frame_max size check Rewrite the oversized-frame check in reader.ReadFrame to compare directly in uint32 (size > max-frameHeaderSize) instead of widening both operands to uint64 (size+frameHeaderSize > max). This is safe from underflow only because maxFrameSize is always either 0 or negotiateFrameSize's frameMinSize floor (4096) or higher. Also add a regression test covering an explicitly unlimited (maxFrameSize == 0) negotiated frame_max with a large frame. | 1 个月前 | |
Fix gen.go, formatting | 2 年前 | |
Revert "Internal 0.9.1 protocol package" This reverts commit f71cf0c006977078069d616a7ebb91d9dfcbc6ba. The internal protocol package uses type identity syntax from go1.9 which is still being used in earlier go versions tracked in #398. | 7 年前 | |
Update deps: use Go 1.20 In #251, we used `URI.Has()` function, which was introduced in Go 1.17. We also have a dependency on uber-go-leak, which requires Go 1.20. In addition, we only test in "oldstable" and "stable" versions in CI. That means, we test in version N and N-1, where N is the latest available version of Go. Signed-off-by: Aitor Perez Cedres <aitor.perez@broadcom.com> | 2 年前 | |
Update deps: use Go 1.20 In #251, we used `URI.Has()` function, which was introduced in Go 1.17. We also have a dependency on uber-go-leak, which requires Go 1.20. In addition, we only test in "oldstable" and "stable" versions in CI. That means, we test in version N and N-1, where N is the latest available version of Go. Signed-off-by: Aitor Perez Cedres <aitor.perez@broadcom.com> | 2 年前 | |
test: retry cleanup connection after clearing memory alarm The broker doesn't lift the memory alarm instantaneously after the watermark is reset, so integrationQueue could return a nil channel in the test cleanup, causing QueueDelete to panic on a nil pointer dereference instead of failing cleanly. Also close the dialed connection in integrationQueue when channel setup fails, so repeated retries don't leak sockets, and widen the retry interval to reduce connection churn against the broker. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> | 1 个月前 | |
feat: skip-and-continue topology recovery with per-entity error surfacing Topology recovery previously aborted on the first entity failure, causing the entire retry cycle to restart even when a single exchange or queue was missing or mis-configured. This change introduces a skip-and-continue model with fine-grained error visibility. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> | 1 个月前 | |
fix: modernize lint issues | 5 个月前 | |
fix: reject frames exceeding negotiated frame_max before allocation (#369) * fix: reject frames exceeding negotiated frame_max before allocation A malicious or compromised broker could declare an oversized length in a frame header (e.g. within a basic.deliver content body frame) and force the client to allocate memory for it, bypassing the frame_max negotiated during connection.tune and enabling a memory-exhaustion DoS. Track the negotiated frame_max in a new atomic Connection.maxFrameSize field, mirrored from Config.FrameSize once connection.tune completes, and check every incoming frame's declared size against it in reader.ReadFrame before dispatching to the type-specific parsers that allocate the payload buffer. Frames over the limit are rejected with ErrFrameTooLarge instead of being read. * refactor: avoid uint64 widening in frame_max size check Rewrite the oversized-frame check in reader.ReadFrame to compare directly in uint32 (size > max-frameHeaderSize) instead of widening both operands to uint64 (size+frameHeaderSize > max). This is safe from underflow only because maxFrameSize is always either 0 or negotiateFrameSize's frameMinSize floor (4096) or higher. Also add a regression test covering an explicitly unlimited (maxFrameSize == 0) negotiated frame_max with a large frame. | 1 个月前 | |
fix: reject frames exceeding negotiated frame_max before allocation (#369) * fix: reject frames exceeding negotiated frame_max before allocation A malicious or compromised broker could declare an oversized length in a frame header (e.g. within a basic.deliver content body frame) and force the client to allocate memory for it, bypassing the frame_max negotiated during connection.tune and enabling a memory-exhaustion DoS. Track the negotiated frame_max in a new atomic Connection.maxFrameSize field, mirrored from Config.FrameSize once connection.tune completes, and check every incoming frame's declared size against it in reader.ReadFrame before dispatching to the type-specific parsers that allocate the payload buffer. Frames over the limit are rejected with ErrFrameTooLarge instead of being read. * refactor: avoid uint64 widening in frame_max size check Rewrite the oversized-frame check in reader.ReadFrame to compare directly in uint32 (size > max-frameHeaderSize) instead of widening both operands to uint64 (size+frameHeaderSize > max). This is safe from underflow only because maxFrameSize is always either 0 or negotiateFrameSize's frameMinSize floor (4096) or higher. Also add a regression test covering an explicitly unlimited (maxFrameSize == 0) negotiated frame_max with a large frame. | 1 个月前 | |
refactor: extract Channel.reopenIfClosed, fix channel-id leak, add error context Move reopenChannelIfClosed out of Connection.recoverConnectionTopology as Channel.reopenIfClosed and extract the c.channels re-registration logic into Connection.reregisterChannel, so the reopen path can be called directly from Channel (channel.go) instead of being redefined as a closure on every recoverConnectionTopology call. No behavior change. Fix a channel-id/registry leak: when per-channel recovery exhausts MaxRetryCount, DefaultConnectionRecovery.OnChannelClose called ch.cleanup directly without releasing the channel from Connection.channels or returning its id to the allocator, permanently leaking both on long-lived connections with recovery enabled. Call ch.connection.releaseChannel(ch) after cleanup. Also give the lifecycle-error wrapping in Channel.shutdown/cleanup and Connection.shutdown/cleanup descriptive context ("channel shutdown error: %w", etc.) instead of a bare fmt.Errorf("%w", e) — errors.As still unwraps to the original *Error, but StateChanged.Err.Error() now indicates which teardown path produced it. --- fix: preserve non-broker recovery errors in StateChanged.Err Channel.cleanup/Connection.cleanup took *Error, so OnChannelClose and OnConnectionClose had to narrow the Reconnect() failure with errors.As(err, &amqpErr) before calling cleanup. Any failure that wasn't a broker *Error (dial errors, TLS/handshake errors, retries exhausted) didn't match, so amqpErr stayed nil and the final StateClosed transition carried Err: nil, discarding the real reason recovery gave up. | 1 个月前 | |
refactor: extract Channel.reopenIfClosed, fix channel-id leak, add error context Move reopenChannelIfClosed out of Connection.recoverConnectionTopology as Channel.reopenIfClosed and extract the c.channels re-registration logic into Connection.reregisterChannel, so the reopen path can be called directly from Channel (channel.go) instead of being redefined as a closure on every recoverConnectionTopology call. No behavior change. Fix a channel-id/registry leak: when per-channel recovery exhausts MaxRetryCount, DefaultConnectionRecovery.OnChannelClose called ch.cleanup directly without releasing the channel from Connection.channels or returning its id to the allocator, permanently leaking both on long-lived connections with recovery enabled. Call ch.connection.releaseChannel(ch) after cleanup. Also give the lifecycle-error wrapping in Channel.shutdown/cleanup and Connection.shutdown/cleanup descriptive context ("channel shutdown error: %w", etc.) instead of a bare fmt.Errorf("%w", e) — errors.As still unwraps to the original *Error, but StateChanged.Err.Error() now indicates which teardown path produced it. --- fix: preserve non-broker recovery errors in StateChanged.Err Channel.cleanup/Connection.cleanup took *Error, so OnChannelClose and OnConnectionClose had to narrow the Reconnect() failure with errors.As(err, &amqpErr) before calling cleanup. Any failure that wasn't a broker *Error (dial errors, TLS/handshake errors, retries exhausted) didn't match, so amqpErr stayed nil and the final StateClosed transition carried Err: nil, discarding the real reason recovery gave up. | 1 个月前 | |
Retry consumer recovery instead of cancelling on a failed re-subscribe recoverConnectionTopology step 5 iterates ch.consumers.configs and, when the recovery-time basic.consume fails, called ch.consumers.cancel(tag). That deletes configs[tag] and closes the caller's delivery channel. configs is the only record this client has of a consumer: there is no recordConsumer counterpart to recordExchange, recordQueue or recordBinding. It is also the map step 5 iterates. Deleting the entry therefore erases the consumer from the client's own topology, so no later recovery attempt can retry it. A single transient failure on one basic.consume, such as a momentary 403 or a reply lost to the socket read deadline, loses that consumer for the life of the connection while recovery reports success and the connection and channel stay open. Steps 1 through 4 handle a failed entity differently: they log, skip, and keep the record, so the next attempt retries it. Step 5 was the only step that destroyed its own retry source. The reference clients agree that a failed re-subscribe is not a cancellation. Neither the Java nor the .NET client removes a recorded consumer when the recovery-time basic.consume fails; both report the failure through their topology recovery exception handler and keep the record. The Java client has retry machinery for exactly this case, in TopologyRecoveryRetryLogic.RECOVER_CONSUMER and RECOVER_PREVIOUS_CONSUMERS. In both clients the recorded consumer is removed only on a client-initiated basic.cancel or on channel teardown. Keep the config and the delivery channel so a later attempt can re-subscribe. This reverses the cleanup added in 3ac961288b, which cancelled the tag so an application would be told to re-Consume() rather than have the library revive the consumer later. The leak that motivated it stays bounded: closeResources calls consumers.close(), which closes every remaining buffer channel and waits on the WaitGroup at channel teardown, and a successful re-subscribe on a later attempt reuses the same entry rather than creating a second one. The failure is still reported through SkippedTopologyEntities on the StateReconnecting to StateOpen transition. A broker-sent basic.cancel is a different event and is unchanged. The inbound case *basicCancel: branch in dispatch() still notifies NotifyCancel listeners and cancels the consumer. Add TestConnectionRecoveryConsumerNotForgottenAfterFailedResubscribe, which holds an exclusive consumer on the target queue for the duration of the first recovery pass so the recovery-time basic.consume fails with 403 ACCESS_REFUSED, releases it, drops the connection again with no obstruction, and then requires a delivery. It fails on the previous behaviour because the delivery channel is closed, and passes now. | 25 天前 | |
fix: typos in comments and tests | 5 个月前 | |
Fix license issue in source headers Claims should be added, following the license file. Signed-off-by: Aitor Perez Cedres <acedres@vmware.com> | 4 年前 | |
run gofumpt -w . | 2 年前 | |
fix: eliminate flakiness in TestTLSHandshake The server-side handshake wait used a 10ms timeout, which is a race against real TLS handshake latency rather than a meaningful assertion. Under load (e.g. parallel test runs), the handshake occasionally took longer than 10ms, failing the test spuriously. Reproduced by running 8 concurrent `go test -race` invocations. Also bind the test TLS server to a dynamic port (127.0.0.1:0) instead of a hardcoded one to avoid collisions with other processes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> | 1 个月前 | |
refactor: remove isRecoverable check in favor of unified recovery shunts Remove the selective `isRecoverable(err)` error classification during channel and connection shutdown phases. Instead, when connection recovery is enabled and an unexpected error occurs, the driver will uniformly execute a minimal transport-only closure, leaving the final destruction of resources completely to the recovery lifecycle cleanups. To implement a resilient "Skip and Continue" topology recovery architecture, channels must not be destructively torn down on soft broker exceptions (such as a 406 PRECONDITION_FAILED due to argument mismatches). Maintaining an exhaustive, hardcoded list of recoverable error codes is incredibly fragile, complex, and prone to hidden regressions if a specific broker or network error frame is missed. 1. **Unified Shutdown Shunts**: Both `Channel.shutdown()` and `Connection.shutdown()` now evaluate a simplified condition: if a non-nil error occurs and recovery is enabled, they perform a minimal transport-only cleanup (`close(ch.errors)`, `close(ch.close)`). This unblocks blocking RPC threads and keeps the client-side consumer layouts intact in memory. 2. **Deterministic Lifecycle Separation**: Graceful user-initiated closes (where `err == nil`) bypass the shunt and immediately run full, destructive teardowns. 3. **Clean Handover of Cleanup Duties**: If automatic recovery fails permanently and exhausts all retries, `Connection.cleanup()` leverages the fully intact `c.channels` registry map to run terminal cleanups, update the public lifecycle states, kill lingering worker routines, and eliminate any `goleak` failures cleanly. ---- Fix integration test TestConnectionRecoveryAutoDeleteExchangeCascade is using recovery enabled connection to create channel. The channel we expect to close as part of verification where auto-delete queues and exchanges are expected to be not present. The broker will close such channel we don't want recovery to happen on these channels. Use a separate non-recovering connection to create such breaking channels | 1 个月前 | |
Add support for unsigned type values Fixes #302 | 5 个月前 | |
fix: URL-encode TLS file paths in URI.String() query string Replace manual string concatenation with url.Values in URI.String() to ensure special characters (such as '&' and '=') in TLS certificate, key, and CA paths are properly encoded. This prevents query parameter injection and ensures correct round-trip parsing of URIs. | 2 个月前 | |
fix: URL-encode TLS file paths in URI.String() query string Replace manual string concatenation with url.Values in URI.String() to ensure special characters (such as '&' and '=') in TLS certificate, key, and CA paths are properly encoded. This prevents query parameter injection and ensures correct round-trip parsing of URIs. | 2 个月前 | |
fix: return error when shortstr exceeds 255 bytes (#354) - Validate the length of short strings in `writeShortstr` and return an error if they exceed the 255-byte limit. - This prevents silent data truncation and integer wrapping (e.g., a 300-byte string wrapping to a length of 44). - Add unit tests in `write_test.go` to verify error handling for oversized short strings and successful serialization for strings at the 255-byte limit. Co-authored-by: Mirah Gary <mirah.gary@broadcom.com> | 2 个月前 | |
fix: return error when shortstr exceeds 255 bytes (#354) - Validate the length of short strings in `writeShortstr` and return an error if they exceed the 255-byte limit. - This prevents silent data truncation and integer wrapping (e.g., a 300-byte string wrapping to a length of 44). - Add unit tests in `write_test.go` to verify error handling for oversized short strings and successful serialization for strings at the 255-byte limit. Co-authored-by: Mirah Gary <mirah.gary@broadcom.com> | 2 个月前 |
Go RabbitMQ 客户端库
这是一个由 RabbitMQ 核心团队 维护的 Go AMQP 0.9.1 客户端。 它最初由 Sean Treadway 开发,代码位于 streadway/amqp。
与 streadway/amqp 的区别
与原始客户端相比,有些地方有所不同,其他则保持不变。
包名
本库使用不同的包名。如果从 streadway/amqp 迁移过来,使用别名可以减少所需的更改数量:
amqp "github.com/rabbitmq/amqp091-go"
许可协议
本客户端采用与原始项目相同的 2 条款 BSD 许可协议。
公共 API 演进
本客户端会尽可能保留关键的 API 元素。 不过,我们也愿意接受社区提出的合理的、不兼容的公共 API 变更建议。 我们没有“永远不进行破坏性公共 API 变更”的规则,并充分认识到良好的客户端 API 会随着时间不断演进。
项目成熟度
本项目基于一个已存在超过十年的成熟 Go 客户端。
支持的 Go 版本
本客户端支持两个最新的 Go 发布系列。
支持的 RabbitMQ 版本
本项目支持从 2.0 开始的 RabbitMQ 版本,但主要针对当前受支持的 RabbitMQ 发布系列进行测试。
某些功能和行为可能特定于服务器版本。
目标
提供一个功能接口,该接口紧密反映 AMQP 0.9.1 模型,并以 RabbitMQ 作为服务器为目标。这包括与协议语义交互所需的最基本功能。
非目标
不打算支持的事项。
- 用于向前或向后兼容的 AMQP 协议协商。
- 0.9.1 版本稳定且已广泛部署。AMQP 1.0 是一个不同的规范(一种不同的协议),应属于另一个库。
- PLAIN 和 EXTERNAL 身份验证机制以外的任何机制。
- 保持机制接口的模块化,使其可以在本包之外进行扩展。如果其他机制被证明很受欢迎,我们将接受补丁以将它们包含在本包中。
- 支持
basic.return和basic.ack帧的顺序。 此客户端使用 Go 通道处理某些协议事件,发送到两个不同通道的事件之间的顺序通常无法保证。
用法
有关简单的生产者和消费者可执行文件,请参见 _examples 子目录。 如果您有一个用例未在示例中得到充分体现,请提交 issue。
文档
贡献
非常欢迎提交拉取请求。请在非 main 分支上创建拉取请求,确保包含能覆盖您所做更改的测试或示例,并且提交的内容应是连贯的变更,其中需说明变更原因。
更多信息请参见 CONTRIBUTING.md。
许可证
BSD 2 条款,详情参见 LICENSE。