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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
//! # AWS Durable Execution SDK for Lambda Rust Runtime
//!
//! This SDK enables Rust developers to build reliable, long-running workflows
//! in AWS Lambda with automatic checkpointing, replay, and state management.
//!
//! ## Overview
//!
//! The AWS Durable Execution SDK provides a framework for building workflows that can
//! survive Lambda function restarts, timeouts, and failures. It automatically checkpoints
//! the state of your workflow, allowing it to resume exactly where it left off after
//! any interruption.
//!
//! ### Key Features
//!
//! - **Automatic Checkpointing**: Every operation is automatically checkpointed, ensuring
//! your workflow can resume from the last completed step.
//! - **Replay Mechanism**: When a function resumes, completed operations return their
//! checkpointed results instantly without re-execution.
//! - **Concurrent Operations**: Process collections in parallel with configurable
//! concurrency limits and failure tolerance.
//! - **External Integration**: Wait for callbacks from external systems with configurable
//! timeouts.
//! - **Type Safety**: Full Rust type safety with generics, trait-based abstractions,
//! and newtype wrappers for domain identifiers.
//! - **Promise Combinators**: Coordinate multiple durable promises with `all`, `any`, `race`, and `all_settled`.
//! - **Replay-Safe Helpers**: Generate deterministic UUIDs and timestamps that are safe for replay.
//! - **Configurable Checkpointing**: Choose between eager, batched, or optimistic checkpointing modes.
//! - **Trait Aliases**: Cleaner function signatures with [`DurableValue`], [`StepError`], and [`StepFuture`] type aliases.
//! - **Sealed Traits**: Internal traits are sealed to allow API evolution without breaking changes.
//!
//! ## Important Documentation
//!
//! Before writing durable workflows, please read:
//!
//! - [`docs::determinism`]: **Critical** - Understanding determinism requirements for replay-safe workflows
//! - [`docs::limits`]: Execution limits and constraints you need to know
//!
//! ## Getting Started
//!
//! Add the SDK to your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! durable-execution-sdk = "0.1"
//! tokio = { version = "1.0", features = ["full"] }
//! serde = { version = "1.0", features = ["derive"] }
//! ```
//!
//! ### Basic Workflow Example
//!
//! Here's a simple workflow that processes an order:
//!
//! ```rust,no_run
//! use durable_execution_sdk::{durable_execution, DurableContext, DurableError, Duration};
//! use serde::{Deserialize, Serialize};
//!
//! #[derive(Deserialize)]
//! struct OrderEvent {
//! order_id: String,
//! amount: f64,
//! }
//!
//! #[derive(Serialize)]
//! struct OrderResult {
//! status: String,
//! order_id: String,
//! }
//!
//! #[durable_execution]
//! async fn process_order(event: OrderEvent, ctx: DurableContext) -> Result<OrderResult, DurableError> {
//! // Step 1: Validate the order (checkpointed automatically)
//! let is_valid: bool = ctx.step(|_step_ctx| async move {
//! // Validation logic here
//! Ok(true)
//! }, None).await?;
//!
//! if !is_valid {
//! return Err(DurableError::execution("Invalid order"));
//! }
//!
//! // Step 2: Process payment (checkpointed automatically)
//! let payment_id: String = ctx.step(|_step_ctx| async move {
//! // Payment processing logic here
//! Ok("pay_123".to_string())
//! }, None).await?;
//!
//! // Step 3: Wait for payment confirmation (suspends Lambda, resumes later)
//! ctx.wait(Duration::from_seconds(5), Some("payment_confirmation")).await?;
//!
//! // Step 4: Complete the order
//! Ok(OrderResult {
//! status: "completed".to_string(),
//! order_id: event.order_id,
//! })
//! }
//! ```
//!
//! ## Core Concepts
//!
//! ### DurableContext
//!
//! The [`DurableContext`] is the main interface for durable operations. It provides:
//!
//! - [`step`](DurableContext::step): Execute and checkpoint a unit of work
//! - [`wait`](DurableContext::wait): Pause execution for a specified duration
//! - [`create_callback`](DurableContext::create_callback): Wait for external systems to signal completion
//! - [`invoke`](DurableContext::invoke): Call other durable Lambda functions
//! - [`map`](DurableContext::map): Process collections in parallel
//! - [`parallel`](DurableContext::parallel): Execute multiple operations concurrently
//! - [`run_in_child_context`](DurableContext::run_in_child_context): Create isolated nested workflows
//!
//! ### Steps
//!
//! Steps are the fundamental unit of work in durable executions. Each step is
//! automatically checkpointed, allowing the workflow to resume from the last
//! completed step after interruptions.
//!
//! ```rust,no_run
//! # use durable_execution_sdk::{DurableContext, StepConfig, StepSemantics};
//! # async fn example(ctx: DurableContext) -> Result<(), Box<dyn std::error::Error>> {
//! // Simple step
//! let result: i32 = ctx.step(|_| async move { Ok(42) }, None).await?;
//!
//! // Named step for better debugging
//! let result: String = ctx.step_named("fetch_data", |_| async move {
//! Ok("data".to_string())
//! }, None).await?;
//!
//! // Step with custom configuration
//! let config = StepConfig {
//! step_semantics: StepSemantics::AtMostOncePerRetry,
//! ..Default::default()
//! };
//! let result: i32 = ctx.step(|_| async move { Ok(42) }, Some(config)).await?;
//! # Ok(())
//! # }
//! ```
//!
//! ### Step Semantics
//!
//! The SDK supports two execution semantics for steps:
//!
//! - **AtLeastOncePerRetry** (default): Checkpoint after execution. The step may
//! execute multiple times if interrupted, but the result is always checkpointed.
//! - **AtMostOncePerRetry**: Checkpoint before execution. Guarantees the step
//! executes at most once per retry, useful for non-idempotent operations.
//!
//! ### Wait Operations
//!
//! Wait operations suspend the Lambda execution and resume after the specified
//! duration. This is efficient because it doesn't block Lambda resources.
//!
//! ```rust,ignore
//! use durable_execution_sdk::Duration;
//!
//! // Wait for 5 seconds
//! ctx.wait(Duration::from_seconds(5), None).await?;
//!
//! // Wait for 1 hour with a name
//! ctx.wait(Duration::from_hours(1), Some("wait_for_approval")).await?;
//! ```
//!
//! ### Callbacks
//!
//! Callbacks allow external systems to signal your workflow. Create a callback,
//! share the callback ID with an external system, and wait for the result.
//!
//! ```rust,ignore
//! use durable_execution_sdk::CallbackConfig;
//!
//! // Create a callback with 24-hour timeout
//! let callback = ctx.create_callback::<ApprovalResponse>(Some(CallbackConfig {
//! timeout: Duration::from_hours(24),
//! ..Default::default()
//! })).await?;
//!
//! // Share callback.callback_id with external system
//! notify_approver(&callback.callback_id).await?;
//!
//! // Wait for the callback result (suspends until callback is received)
//! let approval = callback.result().await?;
//! ```
//!
//! ### Parallel Processing
//!
//! Process collections in parallel with configurable concurrency and failure tolerance:
//!
//! ```rust,ignore
//! use durable_execution_sdk::{MapConfig, CompletionConfig};
//!
//! // Process items with max 5 concurrent executions
//! let results = ctx.map(
//! vec![1, 2, 3, 4, 5],
//! |child_ctx, item, index| async move {
//! child_ctx.step(|_| async move { Ok(item * 2) }, None).await
//! },
//! Some(MapConfig {
//! max_concurrency: Some(5),
//! completion_config: CompletionConfig::all_successful(),
//! ..Default::default()
//! }),
//! ).await?;
//!
//! // Get all successful results
//! let values = results.get_results()?;
//! ```
//!
//! ### Parallel Branches
//!
//! Execute multiple independent operations concurrently:
//!
//! ```rust,ignore
//! use durable_execution_sdk::ParallelConfig;
//!
//! let results = ctx.parallel(
//! vec![
//! |ctx| Box::pin(async move { ctx.step(|_| async move { Ok("a") }, None).await }),
//! |ctx| Box::pin(async move { ctx.step(|_| async move { Ok("b") }, None).await }),
//! |ctx| Box::pin(async move { ctx.step(|_| async move { Ok("c") }, None).await }),
//! ],
//! None,
//! ).await?;
//! ```
//!
//! ### Promise Combinators
//!
//! The SDK provides promise combinators for coordinating multiple durable operations:
//!
//! ```rust,ignore
//! use durable_execution_sdk::DurableContext;
//!
//! async fn coordinate_operations(ctx: &DurableContext) -> Result<(), DurableError> {
//! // Wait for ALL operations to complete successfully
//! let results = ctx.all(vec![
//! ctx.step(|_| async move { Ok(1) }, None),
//! ctx.step(|_| async move { Ok(2) }, None),
//! ctx.step(|_| async move { Ok(3) }, None),
//! ]).await?;
//! // results = [1, 2, 3]
//!
//! // Wait for ALL operations to settle (success or failure)
//! let batch_result = ctx.all_settled(vec![
//! ctx.step(|_| async move { Ok("success") }, None),
//! ctx.step(|_| async move { Err("failure".into()) }, None),
//! ]).await;
//! // batch_result contains both success and failure outcomes
//!
//! // Return the FIRST operation to settle (success or failure)
//! let first = ctx.race(vec![
//! ctx.step(|_| async move { Ok("fast") }, None),
//! ctx.step(|_| async move { Ok("slow") }, None),
//! ]).await?;
//!
//! // Return the FIRST operation to succeed
//! let first_success = ctx.any(vec![
//! ctx.step(|_| async move { Err("fail".into()) }, None),
//! ctx.step(|_| async move { Ok("success") }, None),
//! ]).await?;
//!
//! Ok(())
//! }
//! ```
//!
//! ### Accessing Original Input
//!
//! Access the original input that started the execution:
//!
//! ```rust,ignore
//! use serde::Deserialize;
//!
//! #[derive(Deserialize)]
//! struct OrderEvent {
//! order_id: String,
//! amount: f64,
//! }
//!
//! async fn my_workflow(ctx: DurableContext) -> Result<(), DurableError> {
//! // Get the original input that started this execution
//! let event: OrderEvent = ctx.get_original_input()?;
//! println!("Processing order: {}", event.order_id);
//!
//! // Or get the raw JSON string
//! if let Some(raw_input) = ctx.get_original_input_raw() {
//! println!("Raw input: {}", raw_input);
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! ### Replay-Safe Helpers
//!
//! Generate deterministic values that are safe for replay:
//!
//! ```rust
//! use durable_execution_sdk::replay_safe::{
//! uuid_from_operation, uuid_to_string, uuid_string_from_operation,
//! };
//!
//! // Generate a deterministic UUID from an operation ID
//! let operation_id = "my-operation-123";
//! let uuid_bytes = uuid_from_operation(operation_id, 0);
//! let uuid_string = uuid_to_string(&uuid_bytes);
//!
//! // Or use the convenience function
//! let uuid = uuid_string_from_operation(operation_id, 0);
//!
//! // Same inputs always produce the same UUID
//! let uuid2 = uuid_string_from_operation(operation_id, 0);
//! assert_eq!(uuid, uuid2);
//!
//! // Different seeds produce different UUIDs
//! let uuid3 = uuid_string_from_operation(operation_id, 1);
//! assert_ne!(uuid, uuid3);
//! ```
//!
//! For timestamps, use the execution start time instead of current time:
//!
//! ```rust,ignore
//! use durable_execution_sdk::replay_safe::{
//! timestamp_from_execution, timestamp_seconds_from_execution,
//! };
//!
//! async fn my_workflow(ctx: DurableContext) -> Result<(), DurableError> {
//! // Get replay-safe timestamp (milliseconds since epoch)
//! if let Some(timestamp_ms) = timestamp_from_execution(ctx.state()) {
//! println!("Execution started at: {} ms", timestamp_ms);
//! }
//!
//! // Or get seconds since epoch
//! if let Some(timestamp_secs) = timestamp_seconds_from_execution(ctx.state()) {
//! println!("Execution started at: {} seconds", timestamp_secs);
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! **Important**: See [`docs::determinism`] for detailed guidance on writing replay-safe code.
//!
//! ### Wait Cancellation
//!
//! Cancel an active wait operation:
//!
//! ```rust,ignore
//! async fn cancellable_workflow(ctx: DurableContext) -> Result<(), DurableError> {
//! // Start a long wait in a child context
//! let wait_op_id = ctx.next_operation_id();
//!
//! // In another branch, you can cancel the wait
//! ctx.cancel_wait(&wait_op_id).await?;
//!
//! Ok(())
//! }
//! ```
//!
//! ### Extended Duration Support
//!
//! The Duration type supports extended time periods:
//!
//! ```rust
//! use durable_execution_sdk::Duration;
//!
//! // Standard durations
//! let seconds = Duration::from_seconds(30);
//! let minutes = Duration::from_minutes(5);
//! let hours = Duration::from_hours(2);
//! let days = Duration::from_days(7);
//!
//! // Extended durations
//! let weeks = Duration::from_weeks(2); // 14 days
//! let months = Duration::from_months(3); // 90 days (30 days per month)
//! let years = Duration::from_years(1); // 365 days
//!
//! assert_eq!(weeks.to_seconds(), 14 * 24 * 60 * 60);
//! assert_eq!(months.to_seconds(), 90 * 24 * 60 * 60);
//! assert_eq!(years.to_seconds(), 365 * 24 * 60 * 60);
//! ```
//!
//! ## Type-Safe Identifiers (Newtypes)
//!
//! The SDK provides newtype wrappers for domain identifiers to prevent accidental
//! mixing of different ID types at compile time. These types are available in the
//! [`types`] module and re-exported at the crate root.
//!
//! ### Available Newtypes
//!
//! - [`OperationId`]: Unique identifier for an operation within a durable execution
//! - [`ExecutionArn`]: Amazon Resource Name identifying a durable execution
//! - [`CallbackId`]: Unique identifier for a callback operation
//!
//! ### Creating Newtypes
//!
//! ```rust
//! use durable_execution_sdk::{OperationId, ExecutionArn, CallbackId};
//!
//! // From String or &str (no validation, for backward compatibility)
//! let op_id = OperationId::from("op-123");
//! let op_id2: OperationId = "op-456".into();
//!
//! // With validation (rejects empty strings)
//! let op_id3 = OperationId::new("op-789").unwrap();
//! assert!(OperationId::new("").is_err());
//!
//! // ExecutionArn validates ARN format
//! let arn = ExecutionArn::new("arn:aws:lambda:us-east-1:123456789012:function:my-func:durable:abc123");
//! assert!(arn.is_ok());
//!
//! // CallbackId for external system integration
//! let callback_id = CallbackId::from("callback-xyz");
//! ```
//!
//! ### Using Newtypes as Strings
//!
//! All newtypes implement `Deref<Target=str>` and `AsRef<str>` for convenient string access:
//!
//! ```rust
//! use durable_execution_sdk::OperationId;
//!
//! let op_id = OperationId::from("op-123");
//!
//! // Use string methods directly via Deref
//! assert!(op_id.starts_with("op-"));
//! assert_eq!(op_id.len(), 6);
//!
//! // Use as &str via AsRef
//! let s: &str = op_id.as_ref();
//! assert_eq!(s, "op-123");
//! ```
//!
//! ### Newtypes in Collections
//!
//! All newtypes implement `Hash` and `Eq`, making them suitable for use in `HashMap` and `HashSet`:
//!
//! ```rust
//! use durable_execution_sdk::OperationId;
//! use std::collections::HashMap;
//!
//! let mut results: HashMap<OperationId, String> = HashMap::new();
//! results.insert(OperationId::from("op-1"), "success".to_string());
//! results.insert(OperationId::from("op-2"), "pending".to_string());
//!
//! assert_eq!(results.get(&OperationId::from("op-1")), Some(&"success".to_string()));
//! ```
//!
//! ### Serialization
//!
//! All newtypes use `#[serde(transparent)]` for seamless JSON serialization:
//!
//! ```rust
//! use durable_execution_sdk::OperationId;
//!
//! let op_id = OperationId::from("op-123");
//! let json = serde_json::to_string(&op_id).unwrap();
//! assert_eq!(json, "\"op-123\""); // Serializes as plain string
//!
//! let restored: OperationId = serde_json::from_str(&json).unwrap();
//! assert_eq!(restored, op_id);
//! ```
//!
//! ## Trait Aliases
//!
//! The SDK provides trait aliases to simplify common trait bound combinations.
//! These are available in the [`traits`] module and re-exported at the crate root.
//!
//! ### DurableValue
//!
//! [`DurableValue`] is a trait alias for types that can be durably stored and retrieved:
//!
//! ```rust
//! use durable_execution_sdk::DurableValue;
//! use serde::{Deserialize, Serialize};
//!
//! // DurableValue is equivalent to: Serialize + DeserializeOwned + Send
//!
//! // Any type implementing these traits automatically implements DurableValue
//! #[derive(Debug, Clone, Serialize, Deserialize)]
//! struct OrderResult {
//! order_id: String,
//! status: String,
//! }
//!
//! // Use in generic functions for cleaner signatures
//! fn process_result<T: DurableValue>(result: T) -> String {
//! serde_json::to_string(&result).unwrap_or_default()
//! }
//! ```
//!
//! ## Sealed Traits and Factory Functions
//!
//! Some SDK traits are "sealed" - they cannot be implemented outside this crate.
//! This allows the SDK to evolve without breaking external code. Sealed traits include:
//!
//! - [`Logger`]: For structured logging in durable executions
//! - [`SerDes`]: For custom serialization/deserialization
//!
//! ### Custom Loggers
//!
//! Instead of implementing `Logger` directly, use the factory functions:
//!
//! ```rust
//! use durable_execution_sdk::{custom_logger, simple_custom_logger, LogInfo};
//!
//! // Simple custom logger with a single function for all levels
//! let logger = simple_custom_logger(|level, msg, info| {
//! println!("[{}] {}: {:?}", level, msg, info);
//! });
//!
//! // Full custom logger with separate functions for each level
//! let logger = custom_logger(
//! |msg, info| println!("[DEBUG] {}", msg), // debug
//! |msg, info| println!("[INFO] {}", msg), // info
//! |msg, info| println!("[WARN] {}", msg), // warn
//! |msg, info| println!("[ERROR] {}", msg), // error
//! );
//! ```
//!
//! ### Custom Serializers
//!
//! Instead of implementing `SerDes` directly, use the factory function:
//!
//! ```rust
//! use durable_execution_sdk::serdes::{custom_serdes, SerDesContext, SerDesError};
//!
//! // Create a custom serializer for a specific type
//! let serdes = custom_serdes::<String, _, _>(
//! |value, _ctx| Ok(format!("custom:{}", value)), // serialize
//! |data, _ctx| { // deserialize
//! data.strip_prefix("custom:")
//! .map(|s| s.to_string())
//! .ok_or_else(|| SerDesError::deserialization("Invalid format"))
//! },
//! );
//! ```
//!
//! ## Configuration Types
//!
//! The SDK provides type-safe configuration for all operations:
//!
//! - [`StepConfig`]: Configure retry strategy, execution semantics, and serialization
//! - [`CallbackConfig`]: Configure timeout and heartbeat for callbacks
//! - [`InvokeConfig`]: Configure timeout and serialization for function invocations
//! - [`MapConfig`]: Configure concurrency, batching, and completion criteria for map operations
//! - [`ParallelConfig`]: Configure concurrency and completion criteria for parallel operations
//! - [`CompletionConfig`]: Define success/failure criteria for concurrent operations
//!
//! ### Completion Configuration
//!
//! Control when concurrent operations complete:
//!
//! ```rust
//! use durable_execution_sdk::CompletionConfig;
//!
//! // Complete when first task succeeds
//! let first = CompletionConfig::first_successful();
//!
//! // Wait for all tasks to complete (regardless of success/failure)
//! let all = CompletionConfig::all_completed();
//!
//! // Require all tasks to succeed (zero failure tolerance)
//! let strict = CompletionConfig::all_successful();
//!
//! // Custom: require at least 3 successes
//! let custom = CompletionConfig::with_min_successful(3);
//! ```
//!
//! ## Error Handling
//!
//! The SDK provides a comprehensive error hierarchy through [`DurableError`]:
//!
//! - **Execution**: Errors that return FAILED status without Lambda retry
//! - **Invocation**: Errors that trigger Lambda retry
//! - **Checkpoint**: Checkpoint failures (retriable or non-retriable)
//! - **Callback**: Callback-specific failures
//! - **NonDeterministic**: Replay mismatches (operation type changed between runs)
//! - **Validation**: Invalid configuration or arguments
//! - **SerDes**: Serialization/deserialization failures
//! - **Suspend**: Signal to pause execution and return control to Lambda
//!
//! ```rust,ignore
//! use durable_execution_sdk::DurableError;
//!
//! // Create specific error types
//! let exec_error = DurableError::execution("Something went wrong");
//! let validation_error = DurableError::validation("Invalid input");
//!
//! // Check error properties
//! if error.is_retriable() {
//! // Handle retriable error
//! }
//! ```
//!
//! ## Custom Serialization
//!
//! The SDK uses JSON serialization by default, but you can provide custom
//! serializers by implementing the [`SerDes`] trait:
//!
//! ```rust,ignore
//! use durable_execution_sdk::serdes::{SerDes, SerDesContext, SerDesError};
//!
//! struct MyCustomSerDes;
//!
//! impl SerDes<MyType> for MyCustomSerDes {
//! fn serialize(&self, value: &MyType, context: &SerDesContext) -> Result<String, SerDesError> {
//! // Custom serialization logic
//! Ok(format!("{:?}", value))
//! }
//!
//! fn deserialize(&self, data: &str, context: &SerDesContext) -> Result<MyType, SerDesError> {
//! // Custom deserialization logic
//! todo!()
//! }
//! }
//! ```
//!
//! ## Logging and Tracing
//!
//! The SDK integrates with the `tracing` crate for structured logging. All operations
//! automatically include execution context (ARN, operation ID, parent ID) in log messages.
//!
//! For detailed guidance on configuring tracing for Lambda, log correlation, and best practices,
//! see the [TRACING.md](../docs/TRACING.md) documentation.
//!
//! ### Simplified Logging API
//!
//! The [`DurableContext`] provides convenience methods for logging with automatic context:
//!
//! ```rust,no_run
//! use durable_execution_sdk::{DurableContext, DurableError};
//!
//! async fn my_workflow(ctx: DurableContext) -> Result<(), DurableError> {
//! // Basic logging - context is automatically included
//! ctx.log_info("Starting order processing");
//! ctx.log_debug("Validating input parameters");
//! ctx.log_warn("Retry attempt 2 of 5");
//! ctx.log_error("Failed to process payment");
//!
//! // Logging with extra fields for filtering
//! ctx.log_info_with("Processing order", &[
//! ("order_id", "ORD-12345"),
//! ("customer_id", "CUST-789"),
//! ]);
//!
//! ctx.log_error_with("Payment failed", &[
//! ("error_code", "INSUFFICIENT_FUNDS"),
//! ("amount", "150.00"),
//! ]);
//!
//! Ok(())
//! }
//! ```
//!
//! All logging methods automatically include:
//! - `durable_execution_arn`: The execution ARN for correlation
//! - `parent_id`: The parent operation ID (for nested operations)
//! - `is_replay`: Whether the operation is being replayed
//!
//! ### Extra Fields in Log Output
//!
//! Extra fields passed to `log_*_with` methods are included in the tracing output
//! as key-value pairs, making them queryable in log aggregation systems like CloudWatch:
//!
//! ```rust,ignore
//! // This log message...
//! ctx.log_info_with("Order event", &[
//! ("event_type", "ORDER_CREATED"),
//! ("order_id", "ORD-123"),
//! ]);
//!
//! // ...produces JSON output like:
//! // {
//! // "message": "Order event",
//! // "durable_execution_arn": "arn:aws:...",
//! // "extra": "event_type=ORDER_CREATED, order_id=ORD-123",
//! // ...
//! // }
//! ```
//!
//! ### Replay-Aware Logging
//!
//! The SDK supports replay-aware logging that can suppress or filter logs during replay.
//! This is useful to reduce noise when replaying previously executed operations.
//!
//! ```rust
//! use durable_execution_sdk::{TracingLogger, ReplayAwareLogger, ReplayLoggingConfig};
//! use std::sync::Arc;
//!
//! // Suppress all logs during replay (default)
//! let logger = ReplayAwareLogger::suppress_replay(Arc::new(TracingLogger));
//!
//! // Allow only errors during replay
//! let logger_errors = ReplayAwareLogger::new(
//! Arc::new(TracingLogger),
//! ReplayLoggingConfig::ErrorsOnly,
//! );
//!
//! // Allow all logs during replay
//! let logger_all = ReplayAwareLogger::allow_all(Arc::new(TracingLogger));
//! ```
//!
//! ### Custom Logger
//!
//! You can also provide a custom logger using the factory functions:
//!
//! ```rust
//! use durable_execution_sdk::{custom_logger, simple_custom_logger, LogInfo};
//!
//! // Simple custom logger with a single function for all levels
//! let logger = simple_custom_logger(|level, msg, info| {
//! println!("[{}] {}: {:?}", level, msg, info);
//! });
//!
//! // Full custom logger with separate functions for each level
//! let logger = custom_logger(
//! |msg, info| println!("[DEBUG] {}", msg), // debug
//! |msg, info| println!("[INFO] {}", msg), // info
//! |msg, info| println!("[WARN] {}", msg), // warn
//! |msg, info| println!("[ERROR] {}", msg), // error
//! );
//! ```
//!
//! ## Duration Type
//!
//! The SDK provides a [`Duration`] type with convenient constructors:
//!
//! ```rust
//! use durable_execution_sdk::Duration;
//!
//! let five_seconds = Duration::from_seconds(5);
//! let two_minutes = Duration::from_minutes(2);
//! let one_hour = Duration::from_hours(1);
//! let one_day = Duration::from_days(1);
//!
//! assert_eq!(five_seconds.to_seconds(), 5);
//! assert_eq!(two_minutes.to_seconds(), 120);
//! assert_eq!(one_hour.to_seconds(), 3600);
//! assert_eq!(one_day.to_seconds(), 86400);
//! ```
//!
//! ## Thread Safety
//!
//! The SDK is designed for use in async Rust with Tokio. All core types are
//! `Send + Sync` and can be safely shared across async tasks:
//!
//! - [`DurableContext`] uses `Arc` for shared state
//! - [`ExecutionState`] uses `RwLock` and atomic operations for thread-safe access
//! - Operation ID generation uses atomic counters
//!
//! ## Best Practices
//!
//! 1. **Keep steps small and focused**: Each step should do one thing well.
//! This makes debugging easier and reduces the impact of failures.
//!
//! 2. **Use named operations**: Named steps and waits make logs and debugging
//! much easier to understand.
//!
//! 3. **Handle errors appropriately**: Use `DurableError::execution` for errors
//! that should fail the workflow, and `DurableError::invocation` for errors
//! that should trigger a retry.
//!
//! 4. **Consider idempotency**: For operations that may be retried, ensure they
//! are idempotent or use `AtMostOncePerRetry` semantics.
//!
//! 5. **Use appropriate concurrency limits**: When using `map` or `parallel`,
//! set `max_concurrency` to avoid overwhelming downstream services.
//!
//! 6. **Set reasonable timeouts**: Always configure timeouts for callbacks and
//! invocations to prevent workflows from hanging indefinitely.
//!
//! 7. **Ensure determinism**: Your workflow must execute the same sequence of
//! operations on every run. Avoid using `HashMap` iteration, random numbers,
//! or current time outside of steps. See [`docs::determinism`] for details.
//!
//! 8. **Use replay-safe helpers**: When you need UUIDs or timestamps, use the
//! helpers in [`replay_safe`] to ensure consistent values across replays.
//!
//! 9. **Use type-safe identifiers**: Prefer [`OperationId`], [`ExecutionArn`], and
//! [`CallbackId`] over raw strings to catch type mismatches at compile time.
//!
//! 10. **Use trait aliases**: Use [`DurableValue`] in your generic
//! functions for cleaner, more maintainable signatures.
//!
//! ## Result Type Aliases
//!
//! The SDK provides semantic result type aliases for cleaner function signatures:
//!
//! - [`DurableResult<T>`](DurableResult): Alias for `Result<T, DurableError>` - general durable operations
//! - [`StepResult<T>`](StepResult): Alias for `Result<T, DurableError>` - step operation results
//! - [`CheckpointResult<T>`](CheckpointResult): Alias for `Result<T, DurableError>` - checkpoint operation results
//!
//! ```rust,no_run
//! use durable_execution_sdk::{DurableResult, StepResult, DurableError};
//!
//! // Use in function signatures for clarity
//! fn process_order(order_id: &str) -> DurableResult<String> {
//! Ok(format!("Processed: {}", order_id))
//! }
//!
//! fn execute_step() -> StepResult<i32> {
//! Ok(42)
//! }
//! ```
//!
//! ## Module Organization
//!
//! - [`client`]: Lambda service client for checkpoint operations
//! - [`concurrency`]: Concurrent execution types (BatchResult, ConcurrentExecutor)
//! - [`config`]: Configuration types for all operations
//! - [`context`]: DurableContext, operation identifiers, and logging (includes factory functions
//! [`custom_logger`] and [`simple_custom_logger`] for creating custom loggers)
//! - [`docs`]: **Documentation modules** - determinism requirements and execution limits
//! - [`docs::determinism`]: Understanding determinism for replay-safe workflows
//! - [`docs::limits`]: Execution limits and constraints
//! - [`duration`]: Duration type with convenient constructors
//! - [`error`]: Error types, error handling, and result type aliases ([`DurableResult`], [`StepResult`], [`CheckpointResult`])
//! - [`handlers`]: Operation handlers (step, wait, callback, etc.)
//! - [`lambda`]: Lambda integration types (input/output)
//! - [`operation`]: Operation types and status enums (optimized with `#[repr(u8)]` for compact memory layout)
//! - [`replay_safe`]: Replay-safe helpers for deterministic UUIDs and timestamps
//! - [`serdes`]: Serialization/deserialization system (includes [`custom_serdes`] factory function)
//! - [`state`]: Execution state and checkpointing system
//! - [`traits`]: Trait aliases for common bounds ([`DurableValue`])
//! - [`types`]: Type-safe newtype wrappers for domain identifiers ([`OperationId`], [`ExecutionArn`], [`CallbackId`])
// Private module for sealed trait pattern
// Re-export main types at crate root
pub use ;
pub use *;
pub use ;
pub use Duration;
pub use ;
pub use ;
pub use ;
pub use ;
pub use ;
// Re-export newtype wrappers for domain identifiers
pub use ;
// Re-export trait aliases for common bounds
pub use ;
// Re-export concurrency types
pub use ;
// Re-export handlers
pub use ;
// Re-export replay-safe helpers
pub use ;
// Re-export runtime support
pub use run_durable_handler;
// Re-export termination manager
pub use TerminationManager;
// Re-export structured JSON logger
pub use ;
// Re-export macro if enabled
pub use durable_execution;