Added RabbitMQ
This commit is contained in:
53
src/queue.jl
53
src/queue.jl
@@ -1,10 +1,24 @@
|
||||
# The queue seam.
|
||||
#
|
||||
# The rest of the app only ever calls `enqueue!`, `dequeue!`, and `close!`.
|
||||
# Today those are backed by an in-process, bounded, thread-safe buffer
|
||||
# (the Go-channel / Julia-`Channel` model). To move to RabbitMQ (or any broker)
|
||||
# later, implement a new `JobQueue` subtype with these three methods and swap
|
||||
# the construction in `run`. No HTTP handler or worker code needs to change.
|
||||
# The rest of the app only ever calls `enqueue!`, `dequeue!`, `ack!`, `nack!`
|
||||
# and `close!`. Two implementations sit behind those five methods:
|
||||
#
|
||||
# ChannelQueue in-process, bounded, thread-safe (the Go-channel / Julia-
|
||||
# `Channel` model). Lost on crash: everything still in `spool/`
|
||||
# is re-driven from stage 1 by `recover_dir!`.
|
||||
# RabbitQueue durable RabbitMQ queues (src/rabbit.jl). Survives a crash: a
|
||||
# job stays unacked until its handler commits, so a restart
|
||||
# resumes each file at the stage it had actually reached.
|
||||
#
|
||||
# `FS_QUEUE_BACKEND` picks one; `run` constructs accordingly. No HTTP handler or
|
||||
# worker code knows which it got.
|
||||
#
|
||||
# The ack pair is what makes the broker worth having. Without it a delivery is
|
||||
# settled the moment it is handed to a worker, so a crash mid-handler loses the
|
||||
# job exactly as the in-process queue does, and the network hop buys nothing.
|
||||
# `ChannelQueue` implements both as no-ops, which is honest rather than lazy:
|
||||
# an in-process queue has no delivery to settle, and its recovery story is
|
||||
# `recover_dir!`.
|
||||
|
||||
abstract type JobQueue end
|
||||
|
||||
@@ -34,6 +48,31 @@ queue has been closed *and* fully drained, which is a worker's signal to exit.
|
||||
"""
|
||||
function dequeue! end
|
||||
|
||||
"""
|
||||
ack!(q, job)
|
||||
|
||||
Settle `job` as done: the broker may forget it. Called by `worker_loop` after
|
||||
the handler returns, and after a quarantine, so the message outlives the process
|
||||
for exactly as long as the work is unfinished.
|
||||
|
||||
No-op for `ChannelQueue`.
|
||||
"""
|
||||
function ack! end
|
||||
|
||||
"""
|
||||
nack!(q, job)
|
||||
|
||||
Settle `job` as rejected, without requeueing. Requeueing is deliberately not
|
||||
offered: a job that failed on its bytes will fail again, and redelivering it is
|
||||
a poison-message loop. With no dead-letter exchange configured the broker simply
|
||||
discards it, so this differs from `ack!` only in what it says, not in what
|
||||
happens — which is the point at the one call site that uses it (see
|
||||
`worker_loop`).
|
||||
|
||||
No-op for `ChannelQueue`.
|
||||
"""
|
||||
function nack! end
|
||||
|
||||
"""
|
||||
close!(q)
|
||||
|
||||
@@ -79,6 +118,10 @@ function dequeue!(q::ChannelQueue)::Union{Job,Nothing}
|
||||
end
|
||||
end
|
||||
|
||||
# Nothing to settle: an in-process job was never a delivery.
|
||||
ack!(::ChannelQueue, ::Job) = nothing
|
||||
nack!(::ChannelQueue, ::Job) = nothing
|
||||
|
||||
function close!(q::ChannelQueue)
|
||||
lock(q.cond)
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user