Errors and Graceful Shutdown
There are three distinct outcomes:
BuildError: the runner configuration is invalid;SubmitError: no new work can be accepted;JobError<E>: either the user’sE, or infrastructure stopped before the result sender completed.
Keeping E generic preserves matching on domain failures. Converting every
error into Box<dyn Error> would simplify internals the queue does not actually
need to observe, while weakening the caller.
Graceful shutdown sets accepting = false, signals the dispatcher, closes its
receiver, drains already buffered jobs under the same concurrency limit, joins
running jobs, and notifies every shutdown waiter.
The acceptance boundary is the reserved MPSC permit followed by the shutdown recheck. A job committed before shutdown wins the race and must drain; a job whose permit resolves afterward is rejected. That makes “accepted” an observable ownership transfer rather than a vague timestamp.
Dropping JobHandle does not cancel work. Cancellation would require an
additional explicit contract: a cancellation token, abort handle, or policy for
what dropping means. Version one avoids making a destructor perform surprising
business behavior.