1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
//! Recovery on launch: returning what a previous process abandoned to its queue.
//!
//! **Recovery is a re-enqueue, and that is the whole of it.** A `PENDING` row whose executor is
//! gone goes back to `ENQUEUED`, and whichever executor next polls its queue runs it. This module
//! is one write.
//!
//! Python, TypeScript and Go re-enqueue too (Go's is #433); Java alone runs the recovered
//! workflow in the process that found it.
//!
//! Three things the re-enqueue buys:
//!
//! - **A repeat costs nothing.** The queue's atomic `ENQUEUED` → `PENDING` claim admits exactly
//! one runner, and the `executor_ids` predicate means a second sweep naming the dead executor
//! matches nothing once a live one has taken the row.
//! - **The fleet shares the backlog.** A re-enqueued workflow can be picked up by any executor on
//! the version, so one executor returning to a large backlog does not work through all of it
//! alone.
//! - **Concurrency belongs to the queue, not to this module.** Note that none of the four
//! references gives [`INTERNAL_QUEUE`] a concurrency default, so the answer for a workflow that
//! was never queued is "all of them", by choice rather than by oversight.
//!
//! **Synchronous, inside `launch`.** Not backgrounded, because it is one statement rather than a
//! list of workflows to run — and because doing it before `launch` returns is what keeps it from
//! touching a workflow the application starts the instant it does. Such a workflow is `PENDING`
//! under this executor's id too, and indistinguishable from an abandoned one; a sweep running any
//! later would tear it off its runner and offer it to the fleet. Go orders it the same way, and
//! for the second reason as well: it re-enqueues before the queue runner starts, so recovered work
//! is not racing a dequeue pass that is already in flight.
use crate;
use crate;
/// Returns this executor's abandoned workflows to their queues.
///
/// Called by [`Executor::start`](crate::instance::Executor) before `launch` returns, and reports what
/// moved rather than handles: this process may run none of them.
pub async