1use std::collections::{HashMap, HashSet};
10use std::sync::atomic::{AtomicBool, Ordering};
11use std::sync::{Arc, Condvar, Mutex};
12use std::time::{Duration, SystemTime};
13
14use dex_protocol::dex::{
15 AttributeWrite, ChannelInfo, ChannelMessage as ProtoChannelMessage, ChannelMessageDeletion,
16 ChannelValues, ConditionResults, ConditionStatus, Context as ProtoContext, Kv, StepStreamWrite,
17 Value as ProtoValue, value,
18};
19
20use crate::attribute::{
21 AttributeWriteSettings, require_registered_hard_delete_setting,
22 validate_hard_delete_attribute_write,
23};
24use crate::persistence::PersistenceKind;
25use crate::registry::{RegisteredFlow, decode_instance, physical_name, validate_map_instance};
26use crate::server_protocol::NegotiatedServerProtocolVersion;
27use crate::value_mapper;
28use crate::worker_output::StepOutputEmitter;
29use crate::{
30 Attribute, AttributeMap, Channel, ChannelMap, ChannelMessage, FlowResult, HandlerError,
31 HandlerResult, Stream, Value,
32};
33
34#[derive(Clone, Copy, Eq, PartialEq)]
35pub(crate) enum InvocationMethod {
36 WaitFor,
37 Execute,
38 Rpc,
39}
40
41pub(crate) struct ContextInput {
42 pub(crate) method: InvocationMethod,
43 pub(crate) flow: RegisteredFlow,
44 pub(crate) metadata: ProtoContext,
45 pub(crate) attributes: Vec<Kv>,
46 pub(crate) locals: Vec<Kv>,
47 pub(crate) condition_results: Option<ConditionResults>,
48 pub(crate) channel_infos: HashMap<String, ChannelInfo>,
49 pub(crate) loaded_channel_messages: HashMap<String, ChannelValues>,
50 pub(crate) loaded_attribute_map_instances: Vec<String>,
51 pub(crate) loaded_channel_names: Vec<String>,
52 pub(crate) loaded_channel_map_instances: Vec<String>,
53 pub(crate) negotiated_protocol_version: NegotiatedServerProtocolVersion,
54}
55
56pub(crate) struct InvocationOutputs {
57 pub(crate) attributes: Vec<AttributeWrite>,
58 pub(crate) locals: Vec<Kv>,
59 pub(crate) events: Vec<Kv>,
60 pub(crate) publications: Vec<ProtoChannelMessage>,
61 pub(crate) channel_deletions: Vec<ChannelMessageDeletion>,
62}
63
64#[derive(Clone, Debug, Eq, PartialEq)]
77pub struct RecoveryErrorInfo {
78 detail: String,
79 error_type: String,
80 attempt_progress: StepAttemptProgress,
81}
82
83#[derive(Clone, Copy, Debug, Eq, PartialEq)]
109#[non_exhaustive]
110pub enum StepAttemptProgress {
111 Unspecified,
113 NotStarted,
115 NotCompleted,
117}
118
119impl StepAttemptProgress {
120 fn from_protocol_value(value: i32) -> Self {
121 match dex_protocol::dex::StepAttemptProgress::try_from(value) {
122 Ok(dex_protocol::dex::StepAttemptProgress::NotStarted) => Self::NotStarted,
123 Ok(dex_protocol::dex::StepAttemptProgress::NotCompleted) => Self::NotCompleted,
124 Ok(dex_protocol::dex::StepAttemptProgress::Unspecified) | Err(_) => Self::Unspecified,
125 }
126 }
127}
128
129impl RecoveryErrorInfo {
130 pub fn attempt_progress(&self) -> StepAttemptProgress {
137 self.attempt_progress
138 }
139
140 pub fn detail(&self) -> &str {
142 &self.detail
143 }
144
145 pub fn error_type(&self) -> &str {
147 &self.error_type
148 }
149}
150
151pub struct Context {
167 method: InvocationMethod,
168 flow: RegisteredFlow,
169 output_emitter: Option<StepOutputEmitter>,
170 metadata: ProtoContext,
171 recovery_error: Option<RecoveryErrorInfo>,
172 attributes: HashMap<String, ProtoValue>,
173 locals: HashMap<String, ProtoValue>,
174 condition_results: Option<ConditionResults>,
175 channel_infos: HashMap<String, ChannelInfo>,
176 loaded_channel_messages: HashMap<String, ChannelValues>,
177 loaded_attribute_map_instances: HashSet<String>,
178 loaded_channel_names: HashSet<String>,
179 loaded_channel_map_instances: HashSet<String>,
180 attribute_writes: HashMap<String, AttributeWrite>,
181 local_writes: HashMap<String, Kv>,
182 events: Vec<Kv>,
183 event_names: HashSet<String>,
184 publications: Vec<ProtoChannelMessage>,
185 channel_deletions: Vec<ChannelMessageDeletion>,
186 cancellation: InvocationCancellation,
187 runtime: Option<tokio::runtime::Handle>,
188 step_output_finalizers: Vec<Arc<dyn StepOutputFinalizer>>,
189 step_outputs_finalized: bool,
190 negotiated_protocol_version: NegotiatedServerProtocolVersion,
191 forked_join_names: HashSet<String>,
192}
193
194pub(crate) trait StepOutputFinalizer: Send + Sync {
195 fn finalize_step_output(&self) -> HandlerResult<()>;
196}
197
198impl Context {
199 pub(crate) fn new(
200 input: ContextInput,
201 output_emitter: Option<StepOutputEmitter>,
202 cancellation: InvocationCancellation,
203 ) -> HandlerResult<Self> {
204 let recovery_error =
205 input
206 .metadata
207 .recovery_error
208 .as_ref()
209 .map(|error| RecoveryErrorInfo {
210 attempt_progress: StepAttemptProgress::from_protocol_value(
211 error.attempt_progress,
212 ),
213 detail: error.detail.clone(),
214 error_type: error.error_type.clone(),
215 });
216 Ok(Self {
217 method: input.method,
218 flow: input.flow,
219 output_emitter,
220 metadata: input.metadata,
221 recovery_error,
222 attributes: map_values("Attribute", input.attributes)?,
223 locals: map_values("step-execution local", input.locals)?,
224 condition_results: input.condition_results,
225 channel_infos: input.channel_infos,
226 loaded_channel_messages: input.loaded_channel_messages,
227 loaded_attribute_map_instances: input
228 .loaded_attribute_map_instances
229 .into_iter()
230 .collect(),
231 loaded_channel_names: input.loaded_channel_names.into_iter().collect(),
232 loaded_channel_map_instances: input.loaded_channel_map_instances.into_iter().collect(),
233 attribute_writes: HashMap::new(),
234 local_writes: HashMap::new(),
235 events: Vec::new(),
236 event_names: HashSet::new(),
237 publications: Vec::new(),
238 channel_deletions: Vec::new(),
239 cancellation,
240 runtime: tokio::runtime::Handle::try_current().ok(),
241 step_output_finalizers: Vec::new(),
242 step_outputs_finalized: false,
243 negotiated_protocol_version: input.negotiated_protocol_version,
244 forked_join_names: HashSet::new(),
245 })
246 }
247
248 pub fn flow_id(&self) -> &str {
250 &self.metadata.flow_id
251 }
252
253 pub fn run_id(&self) -> &str {
260 &self.metadata.run_id
261 }
262
263 pub fn flow_started_at(&self) -> SystemTime {
265 system_time(self.metadata.flow_started_timestamp)
266 }
267
268 pub fn step_execution_id(&self) -> &str {
272 &self.metadata.step_execution_id
273 }
274
275 pub fn from_step_execution_id(&self) -> &str {
277 &self.metadata.from_step_execution_id
278 }
279
280 pub(crate) fn record_join_fork(&mut self, join_name: &str) -> HandlerResult<()> {
282 if self.forked_join_names.insert(join_name.to_string()) {
283 return Ok(());
284 }
285 Err(HandlerError::new(
286 "dex_sdk::HandlerError",
287 format!(
288 "Join {join_name} already forked in this invocation; use another Join or fork_with_round_key"
289 ),
290 ))
291 }
292
293 pub fn recovery_error(&self) -> Option<&RecoveryErrorInfo> {
295 self.recovery_error.as_ref()
296 }
297
298 pub fn first_attempt_at(&self) -> SystemTime {
300 system_time(self.metadata.first_attempt_timestamp)
301 }
302
303 pub fn attempt(&self) -> u32 {
311 u32::try_from(self.metadata.attempt).unwrap_or_default()
312 }
313
314 pub fn record_heartbeat(&mut self) -> HandlerResult<()> {
324 self.step_output_emitter()?.send_heartbeat(None)
325 }
326
327 pub fn record_heartbeat_value<T: Value>(&mut self, value: T) -> HandlerResult<()> {
356 let value = value_mapper::encode_handler(&value)?;
357 self.step_output_emitter()?.send_heartbeat(Some(value))
358 }
359
360 pub fn last_heartbeat_value<T: Value>(&self) -> HandlerResult<Option<T>> {
371 if self.method == InvocationMethod::Rpc {
372 return Err(HandlerError::new(
373 "dex_sdk::HandlerError",
374 "Heartbeat values require a Step Context",
375 ));
376 }
377 self.metadata
378 .last_heartbeat_value
379 .as_ref()
380 .map(value_mapper::decode_handler)
381 .transpose()
382 }
383
384 pub fn has_any_timer_fired(&self) -> bool {
386 self.condition_results.as_ref().is_some_and(|results| {
387 results
388 .timer_results
389 .iter()
390 .any(|timer| timer.condition_status == ConditionStatus::Completed as i32)
391 })
392 }
393
394 pub fn has_timer_fired(&self, index: usize) -> bool {
398 self.condition_results
399 .as_ref()
400 .and_then(|results| results.timer_results.get(index))
401 .is_some_and(|timer| timer.condition_status == ConditionStatus::Completed as i32)
402 }
403
404 pub fn wait_for_method_failed(&self) -> bool {
406 self.condition_results
407 .as_ref()
408 .is_some_and(|results| results.wait_for_failed)
409 }
410
411 pub(crate) fn sub_flow_result(&self, index: usize) -> HandlerResult<FlowResult> {
412 if self.method != InvocationMethod::Execute {
413 return Err(HandlerError::new(
414 "dex_sdk::HandlerError",
415 "SubFlow results are available only during execute",
416 ));
417 }
418 let result = self
419 .condition_results
420 .as_ref()
421 .and_then(|results| results.sub_flow_results.get(index))
422 .ok_or_else(|| {
423 HandlerError::new(
424 "dex_sdk::HandlerError",
425 format!("SubFlow result index is unavailable: {index}"),
426 )
427 })?;
428 FlowResult::from_proto(result).map_err(HandlerError::from_error)
429 }
430
431 pub(crate) fn sub_flow_id(&self, index: usize) -> HandlerResult<String> {
432 self.sub_flow_result(index)?;
433 Ok(format!(
434 "SubFlow:{}-{}-{index}",
435 self.flow_id(),
436 self.step_execution_id()
437 ))
438 }
439
440 pub fn wait_for_cancellation(&self) {
444 self.cancellation.wait();
445 }
446
447 pub fn is_cancelled(&self) -> bool {
449 self.cancellation.is_cancelled()
450 }
451
452 pub fn set_step_execution_local<T: Value>(&mut self, key: &str, value: T) -> HandlerResult<()> {
458 require_name(key, "step-execution local key")?;
459 let value = value_mapper::encode_handler(&value)?;
460 self.local_writes.insert(
461 key.to_string(),
462 Kv {
463 key: key.to_string(),
464 value: Some(value),
465 },
466 );
467 Ok(())
468 }
469
470 pub fn step_execution_local<T: Value>(&self, key: &str) -> HandlerResult<T> {
476 require_name(key, "step-execution local key")?;
477 let value = self
478 .local_writes
479 .get(key)
480 .and_then(|entry| entry.value.as_ref())
481 .or_else(|| self.locals.get(key))
482 .ok_or_else(|| {
483 HandlerError::new(
484 "dex_sdk::HandlerError",
485 format!("step-execution local {key} is missing"),
486 )
487 })?;
488 value_mapper::decode_handler(value)
489 }
490
491 pub fn record_event<T: Value>(&mut self, name: &str, value: T) -> HandlerResult<()> {
499 require_name(name, "event name")?;
500 if !self.event_names.insert(name.to_string()) {
501 return Err(HandlerError::new(
502 "dex_sdk::HandlerError",
503 format!("event was already recorded: {name}"),
504 ));
505 }
506 self.events.push(Kv {
507 key: name.to_string(),
508 value: Some(value_mapper::encode_handler(&value)?),
509 });
510 Ok(())
511 }
512
513 pub fn get_attribute<T: Value>(&self, attribute: &Attribute<T>) -> HandlerResult<Option<T>> {
515 self.get_attribute_value(attribute.name(), PersistenceKind::Attribute, None)
516 }
517
518 pub fn get_attribute_map<T: Value>(
520 &self,
521 attribute: &AttributeMap<T>,
522 instance: &str,
523 ) -> HandlerResult<Option<T>> {
524 self.get_attribute_value(
525 attribute.name(),
526 PersistenceKind::AttributeMap,
527 Some(instance),
528 )
529 }
530
531 pub fn set_attribute<T: Value>(
533 &mut self,
534 attribute: &Attribute<T>,
535 value: T,
536 ) -> HandlerResult<()> {
537 self.set_attribute_value(
538 attribute.name(),
539 PersistenceKind::Attribute,
540 None,
541 value_mapper::encode_handler(&value)?,
542 attribute.write_settings(),
543 )
544 }
545
546 pub fn set_attribute_map<T: Value>(
548 &mut self,
549 attribute: &AttributeMap<T>,
550 instance: &str,
551 value: T,
552 ) -> HandlerResult<()> {
553 self.set_attribute_value(
554 attribute.name(),
555 PersistenceKind::AttributeMap,
556 Some(instance),
557 value_mapper::encode_handler(&value)?,
558 attribute.write_settings(),
559 )
560 }
561
562 pub fn delete_attribute<T>(&mut self, attribute: &Attribute<T>) -> HandlerResult<()> {
564 self.set_attribute_value(
565 attribute.name(),
566 PersistenceKind::Attribute,
567 None,
568 value_mapper::deletion(),
569 attribute.write_settings(),
570 )
571 }
572
573 pub fn delete_attribute_map<T>(
575 &mut self,
576 attribute: &AttributeMap<T>,
577 instance: &str,
578 ) -> HandlerResult<()> {
579 self.set_attribute_value(
580 attribute.name(),
581 PersistenceKind::AttributeMap,
582 Some(instance),
583 value_mapper::deletion(),
584 attribute.write_settings(),
585 )
586 }
587
588 pub(crate) fn attribute_map_keys<T>(
589 &self,
590 attribute: &AttributeMap<T>,
591 ) -> HandlerResult<Vec<String>> {
592 self.registered_name(
593 attribute.name(),
594 PersistenceKind::AttributeMap,
595 Some("key-check"),
596 )?;
597 if !self
598 .loaded_attribute_map_instances
599 .contains(&format!("{}/", attribute.name()))
600 {
601 return Err(attribute_map_not_loaded(format!(
602 "all AttributeMap instances were not loaded for this invocation: {}",
603 attribute.name()
604 )));
605 }
606 let prefix = format!("{}/", attribute.name());
607 let mut physical_keys = self
608 .attributes
609 .keys()
610 .filter(|key| key.starts_with(&prefix))
611 .cloned()
612 .collect::<HashSet<_>>();
613 for (key, write) in &self.attribute_writes {
614 if !key.starts_with(&prefix) {
615 continue;
616 }
617 if matches!(
618 write.value.as_ref().and_then(|value| value.kind.as_ref()),
619 Some(value::Kind::NullValue(_))
620 ) {
621 physical_keys.remove(key);
622 } else {
623 physical_keys.insert(key.clone());
624 }
625 }
626 sorted_instance_keys(&prefix, physical_keys)
627 }
628
629 pub fn publish<T: Value>(&mut self, channel: &Channel<T>, value: T) -> HandlerResult<()> {
631 self.publish_value(
632 channel.name(),
633 PersistenceKind::Channel,
634 None,
635 value_mapper::encode_handler(&value)?,
636 )
637 }
638
639 pub fn publish_map<T: Value>(
641 &mut self,
642 channel: &ChannelMap<T>,
643 instance: &str,
644 value: T,
645 ) -> HandlerResult<()> {
646 self.publish_value(
647 channel.name(),
648 PersistenceKind::ChannelMap,
649 Some(instance),
650 value_mapper::encode_handler(&value)?,
651 )
652 }
653
654 pub fn channel_size<T>(&self, channel: &Channel<T>) -> HandlerResult<usize> {
656 self.channel_size_value(channel.name(), PersistenceKind::Channel, None)
657 }
658
659 pub fn channel_map_size<T>(
661 &self,
662 channel: &ChannelMap<T>,
663 instance: &str,
664 ) -> HandlerResult<usize> {
665 self.channel_size_value(channel.name(), PersistenceKind::ChannelMap, Some(instance))
666 }
667
668 pub fn pending_channel_messages<T: Value>(
670 &self,
671 channel: &Channel<T>,
672 ) -> HandlerResult<Vec<ChannelMessage<T>>> {
673 self.pending_channel_messages_value(channel.name(), PersistenceKind::Channel, None)
674 }
675
676 pub fn pending_channel_map_messages<T: Value>(
678 &self,
679 channel: &ChannelMap<T>,
680 instance: &str,
681 ) -> HandlerResult<Vec<ChannelMessage<T>>> {
682 self.pending_channel_messages_value(
683 channel.name(),
684 PersistenceKind::ChannelMap,
685 Some(instance),
686 )
687 }
688
689 pub(crate) fn channel_map_keys<T>(
690 &self,
691 channel: &ChannelMap<T>,
692 ) -> HandlerResult<Vec<String>> {
693 self.registered_name(
694 channel.name(),
695 PersistenceKind::ChannelMap,
696 Some("key-check"),
697 )?;
698 let prefix = format!("{}/", channel.name());
699 let physical_keys = self
700 .channel_infos
701 .iter()
702 .filter(|(key, info)| key.starts_with(&prefix) && info.size > 0)
703 .map(|(key, _)| key.clone())
704 .collect::<HashSet<_>>();
705 sorted_instance_keys(&prefix, physical_keys)
706 }
707
708 pub fn channel_results<T: Value>(&self, channel: &Channel<T>) -> HandlerResult<Vec<T>> {
710 self.channel_results_value(channel.name(), PersistenceKind::Channel, None)
711 }
712
713 pub fn channel_map_results<T: Value>(
715 &self,
716 channel: &ChannelMap<T>,
717 instance: &str,
718 ) -> HandlerResult<Vec<T>> {
719 self.channel_results_value(channel.name(), PersistenceKind::ChannelMap, Some(instance))
720 }
721
722 pub fn write_stream<T: Value>(&mut self, stream: &Stream<T>, value: T) -> HandlerResult<()> {
733 let output_emitter = self.step_output_emitter()?.clone();
734 let definition = self
735 .flow
736 .persistence
737 .get(stream.name())
738 .filter(|definition| {
739 definition.kind == PersistenceKind::Stream
740 && definition.stream_identity == Some(stream.identity())
741 })
742 .ok_or_else(|| {
743 HandlerError::new(
744 "dex_sdk::HandlerError",
745 format!("Stream does not belong to Flow: {}", stream.name()),
746 )
747 })?;
748 if definition.stream_capacity_bytes != Some(stream.stream_capacity_bytes()) {
749 return Err(HandlerError::new(
750 "dex_sdk::HandlerError",
751 format!(
752 "Stream capacity does not match its registered definition: {}",
753 stream.name()
754 ),
755 ));
756 }
757 output_emitter.send_stream_write(StepStreamWrite {
758 stream_name: stream.name().to_string(),
759 stream_capacity_bytes: stream.stream_capacity_bytes(),
760 value: Some(value_mapper::encode_handler(&value)?),
761 })
762 }
763
764 pub(crate) fn prepare_buffered_text_stream(
765 &self,
766 stream: &Stream<String>,
767 ) -> HandlerResult<(
768 StepOutputEmitter,
769 InvocationCancellation,
770 tokio::runtime::Handle,
771 )> {
772 let output_emitter = self.step_output_emitter()?.clone();
773 let definition = self
774 .flow
775 .persistence
776 .get(stream.name())
777 .filter(|definition| {
778 definition.kind == PersistenceKind::Stream
779 && definition.stream_identity == Some(stream.identity())
780 })
781 .ok_or_else(|| {
782 HandlerError::new(
783 "dex_sdk::HandlerError",
784 format!("Stream does not belong to Flow: {}", stream.name()),
785 )
786 })?;
787 if definition.stream_capacity_bytes != Some(stream.stream_capacity_bytes()) {
788 return Err(HandlerError::new(
789 "dex_sdk::HandlerError",
790 format!(
791 "Stream capacity does not match its registered definition: {}",
792 stream.name()
793 ),
794 ));
795 }
796 let runtime = self.runtime.clone().ok_or_else(|| {
797 HandlerError::new(
798 "dex_sdk::HandlerError",
799 "Buffered Stream runtime is unavailable",
800 )
801 })?;
802 Ok((output_emitter, self.cancellation.clone(), runtime))
803 }
804
805 pub(crate) fn register_step_output_finalizer(
806 &mut self,
807 finalizer: Arc<dyn StepOutputFinalizer>,
808 ) -> HandlerResult<()> {
809 if self.step_outputs_finalized {
810 return Err(HandlerError::new(
811 "dex_sdk::HandlerError",
812 "Buffered Stream invocation has finished",
813 ));
814 }
815 self.step_output_finalizers.push(finalizer);
816 Ok(())
817 }
818
819 pub(crate) fn finalize_step_outputs<T>(
820 &mut self,
821 result: HandlerResult<T>,
822 ) -> HandlerResult<T> {
823 if self.step_outputs_finalized {
824 return result;
825 }
826 self.step_outputs_finalized = true;
827 let mut result = result;
828 for finalizer in &self.step_output_finalizers {
829 if let Err(finalization_failure) = finalizer.finalize_step_output() {
830 match &mut result {
831 Ok(_) => result = Err(finalization_failure),
832 Err(handler_failure) => {
833 handler_failure.attach_finalizer_error(&finalization_failure);
834 }
835 }
836 }
837 }
838 result
839 }
840
841 pub(crate) fn cancellation(&self) -> InvocationCancellation {
842 self.cancellation.clone()
843 }
844
845 pub(crate) fn take_outputs(self) -> InvocationOutputs {
846 InvocationOutputs {
847 attributes: self.attribute_writes.into_values().collect(),
848 locals: self.local_writes.into_values().collect(),
849 events: self.events,
850 publications: self.publications,
851 channel_deletions: self.channel_deletions,
852 }
853 }
854
855 fn step_output_emitter(&self) -> HandlerResult<&StepOutputEmitter> {
856 if self.method == InvocationMethod::Rpc {
857 return Err(HandlerError::new(
858 "dex_sdk::HandlerError",
859 "Step progress requires a Step Context",
860 ));
861 }
862 if self.cancellation.is_cancelled() {
863 return Err(HandlerError::new(
864 "dex_sdk::HandlerError",
865 "Step invocation is canceled",
866 ));
867 }
868 self.output_emitter.as_ref().ok_or_else(|| {
869 HandlerError::new("dex_sdk::HandlerError", "Step output stream is unavailable")
870 })
871 }
872
873 fn get_attribute_value<T: Value>(
874 &self,
875 name: &str,
876 kind: PersistenceKind,
877 instance: Option<&str>,
878 ) -> HandlerResult<Option<T>> {
879 let key = self.registered_name(name, kind, instance)?;
880 if kind == PersistenceKind::AttributeMap {
881 let is_loaded = self
882 .loaded_attribute_map_instances
883 .contains(&format!("{name}/"))
884 || self.loaded_attribute_map_instances.contains(&key);
885 if !is_loaded {
886 return Err(attribute_map_not_loaded(format!(
887 "AttributeMap instance was not loaded for this invocation: {key}"
888 )));
889 }
890 }
891 if let Some(write) = self.attribute_writes.get(&key) {
892 let value = write.value.as_ref().ok_or_else(|| {
893 HandlerError::new(
894 "dex_sdk::HandlerError",
895 format!("Attribute write {key} has no Value"),
896 )
897 })?;
898 if matches!(value.kind, Some(value::Kind::NullValue(_))) {
899 return Ok(None);
900 }
901 return value_mapper::decode_handler(value).map(Some);
902 }
903 self.attributes
904 .get(&key)
905 .map(value_mapper::decode_handler)
906 .transpose()
907 }
908
909 fn set_attribute_value(
910 &mut self,
911 name: &str,
912 kind: PersistenceKind,
913 instance: Option<&str>,
914 value: ProtoValue,
915 write_settings: AttributeWriteSettings,
916 ) -> HandlerResult<()> {
917 let key = self.registered_name(name, kind, instance)?;
918 let is_registered_hard_delete_on_null = self
919 .flow
920 .persistence
921 .get(name)
922 .is_some_and(|definition| definition.is_hard_delete_on_null);
923 require_registered_hard_delete_setting(
924 name,
925 is_registered_hard_delete_on_null,
926 write_settings.is_hard_delete_on_null,
927 )
928 .map_err(|error| HandlerError::new("dex_sdk::HandlerError", error))?;
929 let write = write_settings.attribute_write(key.clone(), value);
930 validate_hard_delete_attribute_write(&write)
931 .map_err(|error| HandlerError::new("dex_sdk::HandlerError", error))?;
932 if write.is_hard_delete_on_null {
933 self.negotiated_protocol_version
934 .require_hard_delete_attribute_support(&key)
935 .map_err(|error| HandlerError::new("dex_sdk::HandlerError", error))?;
936 }
937 self.attribute_writes.insert(key, write);
938 Ok(())
939 }
940
941 fn publish_value(
942 &mut self,
943 name: &str,
944 kind: PersistenceKind,
945 instance: Option<&str>,
946 value: ProtoValue,
947 ) -> HandlerResult<()> {
948 let channel_name = self.registered_name(name, kind, instance)?;
949 self.publications.push(ProtoChannelMessage {
950 channel_name: channel_name.clone(),
951 value: Some(value),
952 message_id: String::new(),
953 });
954 self.channel_infos
955 .entry(channel_name)
956 .and_modify(|info| info.size += 1)
957 .or_insert(ChannelInfo { size: 1 });
958 Ok(())
959 }
960
961 pub fn delete_channel_message<T>(
963 &mut self,
964 channel: &Channel<T>,
965 message_id: &str,
966 ) -> HandlerResult<()> {
967 self.delete_channel_message_value(
968 channel.name(),
969 PersistenceKind::Channel,
970 None,
971 message_id,
972 )
973 }
974
975 pub fn delete_channel_map_message<T>(
977 &mut self,
978 channel: &ChannelMap<T>,
979 instance: &str,
980 message_id: &str,
981 ) -> HandlerResult<()> {
982 self.delete_channel_message_value(
983 channel.name(),
984 PersistenceKind::ChannelMap,
985 Some(instance),
986 message_id,
987 )
988 }
989
990 fn delete_channel_message_value(
991 &mut self,
992 name: &str,
993 kind: PersistenceKind,
994 instance: Option<&str>,
995 message_id: &str,
996 ) -> HandlerResult<()> {
997 if message_id.is_empty() {
998 return Err(HandlerError::new(
999 "dex_sdk::HandlerError",
1000 "Channel message ID must not be empty",
1001 ));
1002 }
1003 let channel_name = self.registered_name(name, kind, instance)?;
1004 self.channel_deletions.push(ChannelMessageDeletion {
1005 channel_name: channel_name.clone(),
1006 message_id: message_id.to_string(),
1007 });
1008 if let Some(info) = self.channel_infos.get_mut(&channel_name) {
1009 info.size = info.size.saturating_sub(1);
1010 }
1011 Ok(())
1012 }
1013
1014 fn channel_size_value(
1015 &self,
1016 name: &str,
1017 kind: PersistenceKind,
1018 instance: Option<&str>,
1019 ) -> HandlerResult<usize> {
1020 let channel_name = self.registered_name(name, kind, instance)?;
1021 Ok(self
1022 .channel_infos
1023 .get(&channel_name)
1024 .map_or(0, |info| usize::try_from(info.size).unwrap_or_default()))
1025 }
1026
1027 fn channel_results_value<T: Value>(
1028 &self,
1029 name: &str,
1030 kind: PersistenceKind,
1031 instance: Option<&str>,
1032 ) -> HandlerResult<Vec<T>> {
1033 let channel_name = self.registered_name(name, kind, instance)?;
1034 let Some(results) = &self.condition_results else {
1035 return Ok(Vec::new());
1036 };
1037 let mut decoded = Vec::new();
1038 for result in &results.channel_results {
1039 if result.channel_name == channel_name
1040 && result.condition_status == ConditionStatus::Completed as i32
1041 {
1042 for value in &result.values {
1043 decoded.push(value_mapper::decode_handler(value)?);
1044 }
1045 }
1046 }
1047 Ok(decoded)
1048 }
1049
1050 fn pending_channel_messages_value<T: Value>(
1051 &self,
1052 name: &str,
1053 kind: PersistenceKind,
1054 instance: Option<&str>,
1055 ) -> HandlerResult<Vec<ChannelMessage<T>>> {
1056 let physical_name = self.registered_name(name, kind, instance)?;
1057 let is_loaded = match kind {
1058 PersistenceKind::Channel => self.loaded_channel_names.contains(&physical_name),
1059 PersistenceKind::ChannelMap => {
1060 self.loaded_channel_map_instances
1061 .contains(&format!("{name}/"))
1062 || self.loaded_channel_map_instances.contains(&physical_name)
1063 }
1064 _ => false,
1065 };
1066 if !is_loaded {
1067 return Err(channel_messages_not_loaded(format!(
1068 "Channel messages were not loaded for this invocation: {physical_name}"
1069 )));
1070 }
1071 self.loaded_channel_messages
1072 .get(&physical_name)
1073 .map_or(&[][..], |values| values.messages.as_slice())
1074 .iter()
1075 .map(|message| {
1076 let value = message.value.as_ref().ok_or_else(|| {
1077 HandlerError::new(
1078 "dex_sdk::HandlerError",
1079 format!("Channel message {} has no Value", message.message_id),
1080 )
1081 })?;
1082 Ok(ChannelMessage {
1083 message_id: message.message_id.clone(),
1084 value: value_mapper::decode_handler(value)?,
1085 })
1086 })
1087 .collect()
1088 }
1089
1090 fn registered_name(
1091 &self,
1092 name: &str,
1093 kind: PersistenceKind,
1094 instance: Option<&str>,
1095 ) -> HandlerResult<String> {
1096 let definition = self.flow.persistence.get(name).ok_or_else(|| {
1097 HandlerError::new(
1098 "dex_sdk::HandlerError",
1099 format!("persistence definition does not belong to Flow: {name}"),
1100 )
1101 })?;
1102 if definition.kind != kind {
1103 return Err(HandlerError::new(
1104 "dex_sdk::HandlerError",
1105 format!("persistence definition kind does not match: {name}"),
1106 ));
1107 }
1108 match kind {
1109 PersistenceKind::AttributeMap | PersistenceKind::ChannelMap => {
1110 let instance = instance.ok_or_else(|| {
1111 HandlerError::new(
1112 "dex_sdk::HandlerError",
1113 format!("{name} requires an instance"),
1114 )
1115 })?;
1116 validate_map_instance(instance)
1117 .map_err(|error| HandlerError::new("dex_sdk::HandlerError", error))?;
1118 Ok(physical_name(name, instance))
1119 }
1120 PersistenceKind::Attribute | PersistenceKind::Channel if instance.is_none() => {
1121 Ok(name.to_string())
1122 }
1123 _ => Err(HandlerError::new(
1124 "dex_sdk::HandlerError",
1125 format!("static persistence definition cannot use an instance: {name}"),
1126 )),
1127 }
1128 }
1129}
1130
1131fn attribute_map_not_loaded(message: impl Into<String>) -> HandlerError {
1132 HandlerError::new("dex_sdk::AttributeMapNotLoadedError", message)
1133}
1134
1135fn channel_messages_not_loaded(message: impl Into<String>) -> HandlerError {
1136 HandlerError::new("dex_sdk::ChannelMessagesNotLoadedError", message)
1137}
1138
1139fn sorted_instance_keys(
1140 prefix: &str,
1141 physical_keys: HashSet<String>,
1142) -> HandlerResult<Vec<String>> {
1143 let mut keys = physical_keys
1144 .iter()
1145 .map(|key| {
1146 decode_instance(key, prefix)
1147 .map_err(|error| HandlerError::new("dex_sdk::HandlerError", error))
1148 })
1149 .collect::<HandlerResult<Vec<_>>>()?;
1150 keys.sort();
1151 Ok(keys)
1152}
1153
1154#[derive(Clone)]
1155pub(crate) struct InvocationCancellation {
1156 inner: Arc<InvocationCancellationInner>,
1157}
1158
1159struct InvocationCancellationInner {
1160 cancelled: AtomicBool,
1161 mutex: Mutex<()>,
1162 condition: Condvar,
1163 notification: tokio::sync::Notify,
1164}
1165
1166impl InvocationCancellation {
1167 pub(crate) fn new() -> Self {
1168 Self {
1169 inner: Arc::new(InvocationCancellationInner {
1170 cancelled: AtomicBool::new(false),
1171 mutex: Mutex::new(()),
1172 condition: Condvar::new(),
1173 notification: tokio::sync::Notify::new(),
1174 }),
1175 }
1176 }
1177
1178 fn wait(&self) {
1179 let mut guard = self.inner.mutex.lock().expect("cancellation lock");
1180 while !self.is_cancelled() {
1181 guard = self.inner.condition.wait(guard).expect("cancellation lock");
1182 }
1183 }
1184
1185 pub(crate) fn is_cancelled(&self) -> bool {
1186 self.inner.cancelled.load(Ordering::Acquire)
1187 }
1188
1189 pub(crate) fn cancel(&self) {
1190 let _guard = self.inner.mutex.lock().expect("cancellation lock");
1191 self.inner.cancelled.store(true, Ordering::Release);
1192 self.inner.condition.notify_all();
1193 self.inner.notification.notify_waiters();
1194 }
1195
1196 pub(crate) async fn cancelled(&self) {
1197 let notified = self.inner.notification.notified();
1198 if self.is_cancelled() {
1199 return;
1200 }
1201 notified.await;
1202 }
1203}
1204
1205fn system_time(timestamp: i64) -> SystemTime {
1206 if timestamp >= 0 {
1207 SystemTime::UNIX_EPOCH + Duration::from_secs(timestamp as u64)
1208 } else {
1209 SystemTime::UNIX_EPOCH - Duration::from_secs(timestamp.unsigned_abs())
1210 }
1211}
1212
1213fn map_values(kind: &str, entries: Vec<Kv>) -> HandlerResult<HashMap<String, ProtoValue>> {
1214 let mut mapped = HashMap::new();
1215 for entry in entries {
1216 require_name(&entry.key, kind)?;
1217 let value = entry.value.ok_or_else(|| {
1218 HandlerError::new(
1219 "dex_sdk::HandlerError",
1220 format!("{kind} {} has no Value", entry.key),
1221 )
1222 })?;
1223 if mapped.insert(entry.key.clone(), value).is_some() {
1224 return Err(HandlerError::new(
1225 "dex_sdk::HandlerError",
1226 format!("duplicate {kind} {}", entry.key),
1227 ));
1228 }
1229 }
1230 Ok(mapped)
1231}
1232
1233fn require_name(value: &str, kind: &str) -> HandlerResult<()> {
1234 if value.is_empty() {
1235 Err(HandlerError::new(
1236 "dex_sdk::HandlerError",
1237 format!("{kind} is required"),
1238 ))
1239 } else {
1240 Ok(())
1241 }
1242}
1243
1244#[cfg(test)]
1245#[path = "context_tests.rs"]
1246mod tests;