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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
//! Proc macros for Boson background work.
//!
//! This crate exposes [`task`], an attribute macro that turns an async function into a Boson
//! task with:
//! - a typed params struct (`<FnName>Params`),
//! - a typed enqueue handle (`<TaskName>::send_with`),
//! - and link-time registration (see [Integrating the server](#integrating-the-server) on the
//! [`boson`](https://docs.rs/boson) crate for worker boot).
//!
//! # Define a task
//!
//! ```ignore
//! use boson_core::ExecutionContext;
//!
//! #[boson::task(name = "notify_user")]
//! pub async fn notify_user(
//! ctx: Box<dyn ExecutionContext>,
//! user_id: String,
//! message: String,
//! ) -> boson_core::Result<()> {
//! tracing::info!(actor = ctx.label(), %user_id, %message);
//! Ok(())
//! }
//! ```
//!
//! The first parameter must be `Box<dyn ExecutionContext>`. How that context is built from
//! `actor_json` is configured when the worker boots — see [`ExecutionContext`](https://docs.rs/boson-core/latest/boson_core/trait.ExecutionContext.html)
//! and [`BosonBuilder`](https://docs.rs/boson-runtime/latest/boson_runtime/struct.BosonBuilder.html).
//!
//! # Enqueue work
//!
//! After the worker is running (see [`boson`](https://docs.rs/boson) **Integrating the server**):
//!
//! ```ignore
//! let job_id = NotifyUser::send_with(
//! serde_json::json!({"System": {"operation": "notify"}}),
//! NotifyUserParams {
//! user_id: "user:123".into(),
//! message: "Welcome!".into(),
//! },
//! ).await?;
//! ```
//!
//! Pass the same `actor_json` shape you would use with [`Boson::enqueue`](https://docs.rs/boson-runtime/latest/boson_runtime/struct.Boson.html#method.enqueue).
//!
//! # Project setup (once per crate)
//!
//! - **Depend** — add this crate plus `quark`, `boson-runtime`, `boson-core`, `serde`, and
//! `serde_json` to the crate that owns the handler (see [README](../README.md)).
//! - **Link** — when the handler lives in a library crate, make that crate a dependency of the
//! worker binary so inventory entries are linked (for example `use my_worker as _;` in `main`).
//!
//! # Integrating the server
//!
//! Worker boot (`BosonBuilder`, [`auto_registry`](https://docs.rs/boson-runtime/latest/boson_runtime/struct.BosonBuilder.html#method.auto_registry),
//! [`configure`](https://docs.rs/boson-runtime/latest/boson_runtime/fn.configure.html), identity factory) is **not** repeated for each new task.
//! See the [`boson`](https://docs.rs/boson) crate **Integrating the server** section and the
//! [`task_macro` example](https://github.com/unified-field-dev/boson/blob/main/boson/examples/task_macro.rs).
//!
//! # Generated items
//!
//! For a task function `notify_user` with task name `"notify_user"`, the macro generates:
//!
//! | Item | Purpose |
//! |------|---------|
//! | `NotifyUserParams` | Serde payload struct for task arguments |
//! | `NotifyUser` | Handle type with `send_with(actor_json, params)` |
//! | `__notify_user_impl` | Original function body (internal) |
//!
//! Registration for worker dispatch is emitted at compile time; boot-time collection is described
//! on [`TaskRegistry`](https://docs.rs/boson-runtime/latest/boson_runtime/struct.TaskRegistry.html) and in the [`boson`](https://docs.rs/boson) crate
//! **Integrating the server** section.
//!
//! Task handle names are derived from the **task name** (dots become underscores, `PascalCase`).
//! Params struct names are derived from the **function name**.
//!
//! # Macro attributes
//!
//! `name` is required and must be the first attribute. Additional policy fields seed the initial
//! [`TaskConfig`](https://docs.rs/boson-core/latest/boson_core/struct.TaskConfig.html) on first enqueue (runtime admin may override later):
//!
//! | Attribute | Default | Meaning |
//! |-----------|---------|---------|
//! | `name` | *(required)* | Registry key and enqueue target |
//! | `priority` | `1` | Default priority (lower = higher priority) |
//! | `pool` | `"global"` | Worker pool name |
//! | `idempotency_mode` | *(inherit)* | `"lwt"` or `"none"` (override runtime default) |
//! | `max_attempts` | `3` | Default retry max attempts |
//! | `base_delay_ms` | `1000` | Retry base delay in milliseconds |
//! | `backoff_multiplier` | `2.0` | Retry backoff multiplier |
//! | `max_delay_ms` | `30000` | Retry max delay cap in milliseconds |
//! | `max_in_flight` | `100` | Default max in-flight jobs (`0` = unlimited) |
//! | `max_enqueue_per_second` | `50` | Default enqueue rate limit (`0` = unlimited) |
//!
//! ```ignore
//! #[boson::task(
//! name = "process_order",
//! priority = 10,
//! pool = "checkout",
//! max_in_flight = 200,
//! )]
//! async fn process_order(ctx: Box<dyn ExecutionContext>, order_id: String) -> boson_core::Result<()> {
//! Ok(())
//! }
//! ```
//!
//! # Contract
//!
//! The annotated function must:
//! - be `async`
//! - accept `Box<dyn ExecutionContext>` as the first argument
//! - return `Result<()>` (for example `boson_core::Result<()>`)
//! - include `name = "..."` as the first macro attribute
//!
//! Free functions only — methods with `&self` are rejected at compile time.
use TokenStream;
/// Marks an async function as a Boson task.
///
/// Generates a params struct, a typed enqueue handle, and a registration entry for worker dispatch.
/// See the [crate-level documentation](self) for define/enqueue examples, policy attributes, and
/// worker boot (cross-link to the [`boson`](https://docs.rs/boson) crate).
///
/// # Contract
///
/// - Function must be `async`.
/// - First parameter must be `Box<dyn ExecutionContext>`.
/// - Return type must be `Result<()>` (typically `boson_core::Result<()>`).
/// - `name` attribute is required (must be first).
///
/// # Policy attributes
///
/// Optional: `priority`, `pool`, `idempotency_mode` (`"lwt"` / `"none"`), `max_attempts`, `base_delay_ms`, `backoff_multiplier`,
/// `max_delay_ms`, `max_in_flight`, `max_enqueue_per_second`. See crate docs for defaults.