pub struct WebhookIngress { /* private fields */ }Expand description
The webhook ingress: spool, secret, and one relay per target.
Why: assembled once at startup and shared by the route handler, the metrics
handler, and the background retry sweep, so all three see the same spool.
What: cheap to clone (everything behind Arc).
Test: constructed directly in tests.rs with a temp-dir spool, so no test
mutates a process-global env var.
Implementations§
Source§impl WebhookIngress
impl WebhookIngress
Sourcepub fn new(
spool: Spool,
secret: String,
key_id: String,
targets: Vec<Target>,
) -> Self
pub fn new( spool: Spool, secret: String, key_id: String, targets: Vec<Target>, ) -> Self
Assemble an ingress from explicit parts.
Test: used by every tests.rs case.
Sourcepub fn with_inbox_roots(self, roots: Vec<(String, PathBuf)>) -> Self
pub fn with_inbox_roots(self, roots: Vec<(String, PathBuf)>) -> Self
Meter these inboxes when reporting health.
Why: an acknowledged delivery leaves the spool, so without this the
status goes green while the work sits unprocessed in a target’s inbox.
Test: health_is_degraded_while_a_delivery_sits_undrained.
Sourcepub fn with_red_after(self, red_after: Duration) -> Self
pub fn with_red_after(self, red_after: Duration) -> Self
Override the red-health threshold.
Sourcepub fn with_backoff(self, backoff: BackoffPolicy) -> Self
pub fn with_backoff(self, backoff: BackoffPolicy) -> Self
Override the retry schedule.
Test: the sweep_* and backoff_* cases use a zeroed grace so a sweep
runs without waiting out the real 5 s hold-off.
Sourcepub fn backoff(&self) -> BackoffPolicy
pub fn backoff(&self) -> BackoffPolicy
The retry schedule in force.
Sourcepub fn from_env() -> Result<Self>
pub fn from_env() -> Result<Self>
Production wiring: spool under the console data dir, secret from
SECRET_ENV, and one target per relay-capable service.
Why: the socket paths come from trusty_common::uds::scratch_socket_dir,
the shared entry point #5099 built. That is $TMPDIR/trusty-<uid> with a
/tmp fallback — the base ADR-0034 §3 names, but not the exposure it
objects to: the uid-keyed subdirectory is created at 0700 and owned by
this process, and connect_hardened re-verifies owner and mode before
dialling. #5099 supersedes §3’s “use the service state directory instead”
path rule by making the scratch path satisfy the property §3 wanted.
Nothing binds these sockets until step 4; dialling an absent one is a
clean Unreachable.
What: creates the spool directory eagerly so a misconfigured data dir
fails at startup rather than on the first delivery.
§Errors
When the data directory cannot be resolved or the spool directory cannot be created.
Test: default_spool_root_lives_under_the_console_data_dir, plus the
#[ignore]d integration_from_env_* cases, which point
TRUSTY_DATA_DIR_OVERRIDE at a temp dir under a lock.
Sourcepub async fn health(&self) -> SpoolHealth
pub async fn health(&self) -> SpoolHealth
Scan the spool and classify its health, now.
Deliberately not cached — see health’s module docs. The scan is
filesystem work, so it runs off the async runtime.
Sourcepub async fn ingest(
&self,
source: &str,
headers: &HeaderMap,
body: &[u8],
) -> IngestOutcome
pub async fn ingest( &self, source: &str, headers: &HeaderMap, body: &[u8], ) -> IngestOutcome
Verify, spool, relay — in that order.
Why: the ordering IS the fix; see the module docs. In particular the
spool write happens before this function can return anything a caller
would turn into a 202, and a relay failure never propagates as a
reason to drop the delivery.
What: returns an IngestOutcome; performs no HTTP.
Test: ingest_rejects_an_unknown_source,
ingest_fails_closed_when_no_secret_is_configured,
ingest_rejects_a_forged_signature,
ingest_returns_spool_failed_and_never_accepts_when_the_write_fails,
ingest_accepts_and_deletes_on_an_explicit_ack,
relay_failure_leaves_a_pending_entry_with_an_incremented_attempt_count.
Sourcepub async fn retry_pending_once(&self) -> SweepReport
pub async fn retry_pending_once(&self) -> SweepReport
Re-attempt every pending delivery that is due, once.
Why: ADR-0034 §2 — “Console retries with backoff.” Three guards, each closing a different failure:
- Backoff (
BackoffPolicy::is_due) — without it every pending entry is re-relayed on every tick and each non-ack rewrites the whole base64 body plus twofsyncs. Until step 4 binds a listener that is every delivery, forever. - Claims (
schedule::ClaimSet) — without them a tick landing inside the ≤5 s relay window sends a delivery the request path is still sending. One delivery, two relays. - [
SWEEP_BUDGET] — the pass is serial and each relay can burn its full timeout, so an unbounded pass can outlast its own tick interval.
Nothing any guard skips is dropped: it stays pending, durable, and
visible to WebhookIngress::health, which scans on the request rather
than trusting this loop to still be alive.
What: relays each due entry, deleting only on an explicit ack. Returns per-sweep counts.
Test: retry_sweep_acks_and_clears_a_pending_entry,
retry_sweep_leaves_an_unrelayable_entry_pending_with_more_attempts,
sweep_does_not_relay_an_entry_the_request_path_is_still_relaying,
sweep_honours_backoff_between_ticks,
sweep_stops_relaying_an_exhausted_entry.
Trait Implementations§
Source§impl Clone for WebhookIngress
impl Clone for WebhookIngress
Source§fn clone(&self) -> WebhookIngress
fn clone(&self) -> WebhookIngress
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for WebhookIngress
impl !UnwindSafe for WebhookIngress
impl Freeze for WebhookIngress
impl Send for WebhookIngress
impl Sync for WebhookIngress
impl Unpin for WebhookIngress
impl UnsafeUnpin for WebhookIngress
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more