Documentation
¶
Overview ¶
Package azurequeue provides a local, in-memory emulation of Azure Queue Storage's REST+XML wire protocol (queue CRUD plus the full message lifecycle: put/get/peek/delete/update-visibility/clear), Azurite-compatible enough for unmodified azure-sdk-for-go clients to operate against. See AZURE.md and PARITY.md for scope and known gaps.
Index ¶
- Constants
- Variables
- type ConfigProvider
- type Handler
- func (h *Handler) ExtractOperation(c *echo.Context) string
- func (h *Handler) ExtractResource(c *echo.Context) string
- func (h *Handler) GetSupportedOperations() []string
- func (h *Handler) Handler() echo.HandlerFunc
- func (h *Handler) MatchPriority() int
- func (h *Handler) Name() string
- func (h *Handler) Reset()
- func (h *Handler) Restore(ctx context.Context, data []byte) error
- func (h *Handler) RouteMatcher() service.Matcher
- func (h *Handler) Shutdown(ctx context.Context)
- func (h *Handler) Snapshot(ctx context.Context) []byte
- func (h *Handler) StartWorker(ctx context.Context) error
- func (h *Handler) WithJanitor(interval time.Duration) *Handler
- type InMemoryBackend
- func (b *InMemoryBackend) ClearMessages(queue string) error
- func (b *InMemoryBackend) CreateQueue(name string) (bool, error)
- func (b *InMemoryBackend) DeleteMessage(queue, messageID, popReceipt string) error
- func (b *InMemoryBackend) DeleteQueue(name string) error
- func (b *InMemoryBackend) GetMessages(queue string, numOfMessages int, visibilityTimeout time.Duration) ([]MessageInfo, error)
- func (b *InMemoryBackend) ListQueues() []QueueInfo
- func (b *InMemoryBackend) PeekMessages(queue string, numOfMessages int) ([]MessageInfo, error)
- func (b *InMemoryBackend) PutMessage(queue, text string, visibilityTimeout, ttl time.Duration) (MessageInfo, error)
- func (b *InMemoryBackend) Reset()
- func (b *InMemoryBackend) Restore(ctx context.Context, data []byte) error
- func (b *InMemoryBackend) Snapshot(ctx context.Context) []byte
- func (b *InMemoryBackend) UpdateMessage(queue, messageID, popReceipt string, visibilityTimeout time.Duration, ...) (MessageInfo, error)
- type Janitor
- type MessageInfo
- type Provider
- type QueueInfo
- type Settings
- type StorageBackend
Constants ¶
const ( // DefaultVisibilityTimeout is applied when a caller omits // visibilitytimeout on Put Message / Get Messages. DefaultVisibilityTimeout = 30 * time.Second // DefaultMessageTTL is applied when a caller omits messagettl on Put // Message (or passes -1, Azure's "infinite" sentinel is not modeled -- // see PARITY.md known gaps). DefaultMessageTTL = 7 * 24 * time.Hour // MaxNumOfMessages is the largest numofmessages Get/Peek Messages // accepts per call. MaxNumOfMessages = 32 // MinNumOfMessages is the smallest numofmessages Get/Peek Messages // accepts per call. MinNumOfMessages = 1 )
Default and bound values for Put/Get Messages query parameters, matching real Azure Queue Storage's documented limits.
const DefaultPort = 10001
DefaultPort is Azure Queue's fixed, protocol-conventional TCP port. This follows the same pattern as services/azureblob's DefaultPort (10000) and, before that, services/iot's MQTT broker (1883): pick one default and try to bind exactly that, rather than drawing from cli.go's shared --port-range-start/--port-range-end PortAlloc pool (used for on-demand ephemeral resources like Lambda function URLs and ElastiCache, not fixed service ports) or inventing an alternative numbering scheme. The default value itself (10001) is Azurite's own Queue service port, so unmodified UseDevelopmentStorage=true-style SDK configuration works out of the box; see AZURE.md section 4 for the full rationale, including why this deliberately does NOT fall back into the shared PortAlloc pool if 10001 is taken (StartWorker fails fast instead -- see handler.go).
Variables ¶
var ( ErrQueueNotFound = errors.New("azurequeue: queue not found") ErrQueueAlreadyExists = errors.New("azurequeue: queue already exists with different metadata") ErrMessageNotFound = errors.New("azurequeue: message not found") ErrPopReceiptMismatch = errors.New("azurequeue: pop receipt mismatch") ErrInvalidQueryParam = errors.New("azurequeue: invalid query parameter value") ErrOutOfRangeQueryParam = errors.New("azurequeue: query parameter value out of range") // ErrSnapshotQueueNull and ErrSnapshotMessageNull are returned by Restore // when a snapshot's "queues" map (or a queue's "Messages" slice) holds a // JSON null entry, which decodes to a nil pointer that would panic on // first dereference if stored as-is. See persistence.go. ErrSnapshotQueueNull = errors.New("azurequeue: restore snapshot: queue is null") ErrSnapshotMessageNull = errors.New("azurequeue: restore snapshot: message is null") // ErrSnapshotQueueNameMismatch is returned by Restore when a snapshot's // "queues" map key differs from that entry's storedQueue.Name. Queue // operations (CreateQueue, DeleteQueue, PutMessage, ...) all key off the // map, while ListQueues reads Name -- a mismatch would let those two // views disagree about a queue's identity. See persistence.go. ErrSnapshotQueueNameMismatch = errors.New("azurequeue: restore snapshot: queue map key does not match Name") )
Sentinel errors for Azure Queue Storage operations.
var ErrNilAppContext = errors.New("azurequeue: nil app context")
ErrNilAppContext is returned when Init is called with a nil AppContext.
Functions ¶
This section is empty.
Types ¶
type ConfigProvider ¶
type ConfigProvider interface {
GetAzureQueueSettings() Settings
}
ConfigProvider is a private interface to extract AzureQueue configuration from the abstract AppContext Config, mirroring services/azureblob.ConfigProvider.
type Handler ¶
type Handler struct {
Backend StorageBackend
// Endpoint is e.g. "http://127.0.0.1:10001" -- used to build
// ServiceEndpoint in List Queues responses.
Endpoint string
// Port is the TCP port StartWorker binds. Set from Settings at Init time
// (see provider.go); defaults to DefaultPort. Like services/azureblob,
// this is a single fixed, protocol-conventional port -- there is no
// fallback pool, so StartWorker fails fast if it's unavailable rather
// than silently binding a different port.
Port int
// contains filtered or unexported fields
}
Handler is the Echo HTTP handler for Azure Queue Storage operations.
func NewHandler ¶
func NewHandler(backend StorageBackend) *Handler
NewHandler creates a new Azure Queue Handler. Port defaults to DefaultPort; callers (typically provider.go) override it from Settings.
func (*Handler) ExtractOperation ¶
ExtractOperation extracts the Azure Queue operation name from the request, for metrics labeling.
func (*Handler) ExtractResource ¶
ExtractResource extracts the queue/message resource identifier from the request path, for metrics labeling.
func (*Handler) GetSupportedOperations ¶
GetSupportedOperations returns the list of supported Azure Queue operations.
func (*Handler) Handler ¶
func (h *Handler) Handler() echo.HandlerFunc
Handler returns the Echo handler function for Azure Queue operations.
func (*Handler) MatchPriority ¶
MatchPriority returns the routing priority for the AzureQueue handler. Irrelevant in practice since RouteMatcher never matches; 0 (lowest) is the safe default.
func (*Handler) Reset ¶
func (h *Handler) Reset()
Reset clears all in-memory state from the backend. It is used by the POST /_gopherstack/reset endpoint for CI pipelines and rapid local development.
func (*Handler) RouteMatcher ¶
RouteMatcher exists only to satisfy service.Registerable's interface contract: like services/azureblob, AzureQueue deliberately never matches on the shared AWS single-port Router. It runs on its own dedicated listener started by StartWorker (see provider.go for the full rationale). AzureQueue's Provider IS registered in cli.go's getMostRecentServiceProviders like every other service -- startBackgroundWorkers calls StartWorker via the service.BackgroundWorker interface regardless of routing, which is how the dedicated listener comes up. Only RouteMatcher itself is inert, kept so *Handler satisfies service.Registerable.
func (*Handler) Shutdown ¶
Shutdown stops the dedicated Queue listener. A graceful Shutdown error (e.g. its context expiring before active connections finish) is logged and followed by Close, which forcibly closes the listener and any remaining idle/active connections; any Close error is logged too rather than leaving the listener to leak silently.
func (*Handler) Snapshot ¶
Snapshot implements persistence.Persistable by delegating to the backend.
func (*Handler) StartWorker ¶
StartWorker binds the dedicated Queue listener, starts serving on it, and -- if WithJanitor was called -- starts the background TTL-expiry sweep. See provider.go's Provider doc comment for why AzureQueue needs its own listener instead of registering into the shared AWS Router, and services/azureblob's StartWorker for the synchronous-bind rationale this mirrors exactly.
func (*Handler) WithJanitor ¶
WithJanitor attaches a background TTL-expiry janitor to the handler, mirroring services/xray's WithJanitor. If Backend is not an *InMemoryBackend the call is a no-op (a fake StorageBackend in tests has no sweepable state).
type InMemoryBackend ¶
type InMemoryBackend struct {
// contains filtered or unexported fields
}
InMemoryBackend implements StorageBackend using in-memory maps guarded by a single RWMutex. Shaped after services/azureblob's InMemoryBackend.
func NewInMemoryBackend ¶
func NewInMemoryBackend() *InMemoryBackend
NewInMemoryBackend creates a new empty InMemoryBackend.
func (*InMemoryBackend) ClearMessages ¶
func (b *InMemoryBackend) ClearMessages(queue string) error
ClearMessages removes every message from queue. Returns ErrQueueNotFound if the queue does not exist.
func (*InMemoryBackend) CreateQueue ¶
func (b *InMemoryBackend) CreateQueue(name string) (bool, error)
CreateQueue creates a new, empty queue. If a queue with the same name already exists, created is false and err is nil -- this backend has no queue metadata (see PARITY.md known gaps), so any pre-existing queue is by definition "the same metadata" and Create is idempotent (204), matching real Azure Queue Storage's semantics for a metadata-identical retry. ErrQueueAlreadyExists is reserved for a future metadata-bearing Create.
func (*InMemoryBackend) DeleteMessage ¶
func (b *InMemoryBackend) DeleteMessage(queue, messageID, popReceipt string) error
DeleteMessage removes a message identified by messageID from queue, after verifying popReceipt matches its current value. Returns ErrQueueNotFound, ErrMessageNotFound, or ErrPopReceiptMismatch as appropriate.
func (*InMemoryBackend) DeleteQueue ¶
func (b *InMemoryBackend) DeleteQueue(name string) error
DeleteQueue removes a queue and all of its messages. Returns ErrQueueNotFound if the queue does not exist.
func (*InMemoryBackend) GetMessages ¶
func (b *InMemoryBackend) GetMessages( queue string, numOfMessages int, visibilityTimeout time.Duration, ) ([]MessageInfo, error)
GetMessages dequeues up to numOfMessages visible, non-expired messages from queue: each returned message is hidden for visibilityTimeout (its NextVisibleTime advances, so subsequent Get/Peek calls skip it until that timeout elapses), assigned a fresh PopReceipt, and has its DequeueCount incremented. Returns ErrQueueNotFound if the queue does not exist.
func (*InMemoryBackend) ListQueues ¶
func (b *InMemoryBackend) ListQueues() []QueueInfo
ListQueues returns a snapshot of all queues, sorted by name (the order Azure's List Queues returns them in).
func (*InMemoryBackend) PeekMessages ¶
func (b *InMemoryBackend) PeekMessages(queue string, numOfMessages int) ([]MessageInfo, error)
PeekMessages returns up to numOfMessages visible, non-expired messages from queue without changing their visibility, PopReceipt, or DequeueCount. Returns ErrQueueNotFound if the queue does not exist.
func (*InMemoryBackend) PutMessage ¶
func (b *InMemoryBackend) PutMessage(queue, text string, visibilityTimeout, ttl time.Duration) (MessageInfo, error)
PutMessage enqueues a new message on queue. visibilityTimeout delays the message's initial visibility (0 means immediately visible); ttl bounds how long the message survives before the janitor sweeps it (0 uses DefaultMessageTTL). Returns ErrQueueNotFound if the queue does not exist.
func (*InMemoryBackend) Reset ¶
func (b *InMemoryBackend) Reset()
Reset clears all in-memory state. It is used by the POST /_gopherstack/reset endpoint for CI pipelines and rapid local development.
func (*InMemoryBackend) Restore ¶
func (b *InMemoryBackend) Restore(ctx context.Context, data []byte) error
Restore loads backend state from a JSON snapshot. It implements persistence.Persistable.
func (*InMemoryBackend) Snapshot ¶
func (b *InMemoryBackend) Snapshot(ctx context.Context) []byte
Snapshot serialises the backend state to JSON. It implements persistence.Persistable.
func (*InMemoryBackend) UpdateMessage ¶
func (b *InMemoryBackend) UpdateMessage( queue, messageID, popReceipt string, visibilityTimeout time.Duration, text *string, ) (MessageInfo, error)
UpdateMessage sets a new visibility timeout (and, if text is non-nil, replaces the message body) for messageID after verifying popReceipt matches, then rotates the PopReceipt. Returns ErrQueueNotFound, ErrMessageNotFound, or ErrPopReceiptMismatch as appropriate.
type Janitor ¶
type Janitor struct {
Backend *InMemoryBackend
Interval time.Duration
}
Janitor is the Azure Queue background worker that deletes messages whose message TTL (see PutMessage's ttl parameter / DefaultMessageTTL) has elapsed, mirroring services/sqs's Janitor (SQS's MessageRetentionPeriod sweep).
func NewJanitor ¶
func NewJanitor(backend *InMemoryBackend, interval time.Duration) *Janitor
NewJanitor creates a new Azure Queue Janitor for the given backend.
type MessageInfo ¶
type MessageInfo struct {
InsertionTime time.Time
ExpirationTime time.Time
TimeNextVisible time.Time
ID string
PopReceipt string
Text string
DequeueCount int64
}
MessageInfo is a read-only snapshot of a message, returned by the StorageBackend message accessors. PopReceipt is empty for Peek Messages (peeking never assigns one -- see AZURE.md section 2), and Text is only populated for Get/Peek (Put/Update return no body, only metadata, mirroring real Azure Queue Storage).
type Provider ¶
type Provider struct{}
Provider implements service.Provider for the Azure Queue Storage service.
Like services/azureblob, AzureQueue does not register a RouteMatcher into the shared AWS single-port Router: Azure Queue's path shape (/<account>/<queue>[/messages[/<id>]]) has no service-identifying header the way AWS's X-Amz-Target does, and shares the same /<account>/<resource> shape as Azure Blob and Table, so multiplexing it onto the shared port (or even onto Azure Blob's own dedicated port) risks exactly the collision the router avoids by construction for AWS services (see AZURE.md section 4). Instead the returned Handler implements service.BackgroundWorker and stands up its own dedicated *echo.Echo/*http.Server, listening on a fixed, protocol-conventional port (Azurite's own Queue port, 10001). It is registered in cli.go's getMostRecentServiceProviders like every other provider; only its RouteMatcher (which always returns false) is inert.
func (*Provider) Init ¶
func (p *Provider) Init(ctx *service.AppContext) (service.Registerable, error)
Init initializes the AzureQueue service backend and handler. The configured port (Settings.Port, default DefaultPort) is only recorded here; the actual TCP bind happens synchronously in Handler.StartWorker, so a port-in-use failure is returned to the caller directly instead of being discovered later from a background goroutine.
type QueueInfo ¶
QueueInfo is a read-only snapshot of a queue's metadata, returned by StorageBackend.ListQueues. It intentionally excludes the queue's message slice so callers cannot mutate backend state through it.
type Settings ¶
type Settings struct {
// Port is the fixed TCP port for the dedicated Queue listener. See
// handler.go's StartWorker for what happens when it's unavailable
// (fails fast; no fallback pool, matching services/azureblob).
Port int `` //nolint:lll // config struct tags are intentionally verbose
/* 178-byte string literal not displayed */
}
Settings holds service-level configuration for the Azure Queue backend. Fields are picked up by the Kong CLI parser when this struct is embedded in the root CLI command (see cli.go's CLI.AzureQueue field), mirroring services/azureblob's Settings pattern.
func DefaultSettings ¶
func DefaultSettings() Settings
DefaultSettings returns the default Settings. Used when no ConfigProvider is available at init time (e.g. tests constructing a Provider directly).
type StorageBackend ¶
type StorageBackend interface {
CreateQueue(name string) (created bool, err error)
DeleteQueue(name string) error
ListQueues() []QueueInfo
PutMessage(queue, text string, visibilityTimeout, ttl time.Duration) (MessageInfo, error)
// GetMessages and PeekMessages return ErrOutOfRangeQueryParam if
// numOfMessages is outside [MinNumOfMessages, MaxNumOfMessages] -- a
// defense-in-depth check against direct callers that bypass the
// handler's own range validation (see messages.go's parseNumOfMessages),
// since an unvalidated negative value would otherwise panic on
// allocation.
GetMessages(queue string, numOfMessages int, visibilityTimeout time.Duration) ([]MessageInfo, error)
PeekMessages(queue string, numOfMessages int) ([]MessageInfo, error)
DeleteMessage(queue, messageID, popReceipt string) error
UpdateMessage(
queue, messageID, popReceipt string, visibilityTimeout time.Duration, text *string,
) (MessageInfo, error)
ClearMessages(queue string) error
// Reset clears all in-memory state. Used by the
// POST /_gopherstack/reset endpoint for CI pipelines and rapid local development.
Reset()
}
StorageBackend defines the interface for an Azure Queue Storage backend. Shaped after services/azureblob's StorageBackend: a narrow, testable seam between the wire handler and storage, so handler tests can substitute a fake.