sofie_db/worker/
context.rs1use std::sync::Arc;
2
3use serde_json::Value;
4use sofie_auth::SigningKeys;
5use sofie_core::{Error, Result, Uuid};
6
7use crate::{Claimed, Context, Db, Outcome, Reach, Step, Writes};
8
9pub struct JobContext {
10 pub(crate) db: Db,
11 pub(crate) payload: Value,
12 event: Option<&'static str>,
13 actor: Option<Uuid>,
14 completion: Step,
15 #[cfg(feature = "remote-contracts")]
16 pub(crate) message: sofie_core::Uuid,
17 #[cfg(feature = "idempotency")]
19 pub(crate) work: crate::Work,
20 #[cfg(feature = "contracts")]
21 pub(crate) retried_for: std::time::Duration,
22}
23
24impl JobContext {
25 pub(super) fn new(
26 worker: &super::Worker,
27 message: &Claimed,
28 event: Option<&'static str>,
29 completion: Step,
30 ) -> Self {
31 Self {
32 db: worker.db.clone(),
33 payload: message.payload.clone(),
34 event,
35 actor: message.actor,
36 completion,
37 #[cfg(feature = "remote-contracts")]
38 message: message.id,
39 #[cfg(feature = "idempotency")]
40 work: crate::Work::new(message.id.to_string(), message.name.clone()),
41 #[cfg(feature = "contracts")]
42 retried_for: super::backoff::retried_for(worker.max_attempts),
43 }
44 }
45
46 pub fn signing_keys(&self) -> Result<Arc<SigningKeys>> {
48 self.db.signing_keys().ok_or_else(|| {
49 Error::internal_message(
50 "the worker's database has no signing keys; give it the app's with \
51 `Db::with_signing_keys`",
52 )
53 })
54 }
55
56 pub(crate) async fn complete(self, outcome: &mut dyn Outcome) -> Result<()> {
57 let reach = self.reach();
58 self.db
59 .commit_with(outcome, vec![self.completion], reach)
60 .await
61 }
62}
63
64impl Context for JobContext {
66 fn db(&self) -> &Db {
67 &self.db
68 }
69
70 fn reach(&self) -> Reach {
71 self.actor.map_or(Reach::All, Reach::AllAs)
72 }
73
74 fn bound(&self, name: &str) -> Result<Uuid> {
76 self.payload
77 .get(name)
78 .and_then(Value::as_str)
79 .and_then(|text| text.parse().ok())
80 .ok_or_else(|| Error::internal_message(format!("the payload has no id named `{name}`")))
81 }
82
83 #[cfg(feature = "jobs")]
84 fn input(&mut self) -> Result<Value> {
85 Ok(self.payload.clone())
86 }
87
88 fn event(&self, name: &str) -> Result<Value> {
89 match self.event {
90 Some(delivered) if delivered == name => Ok(self.payload.clone()),
91 Some(delivered) => Err(Error::internal_message(format!(
92 "this listener receives `{delivered}`, so it cannot take a `{name}`"
93 ))),
94 None => Err(Error::internal_message(format!(
95 "a scheduled job receives no event, so it cannot take a `{name}`"
96 ))),
97 }
98 }
99}
100
101impl Writes for JobContext {}