@@ -10,7 +10,7 @@ use crate::{
1010} ;
1111
1212#[ cfg( feature = "webhooks" ) ]
13- use crate :: { streaming :: StreamBackend , webhooks:: WebhookConfig } ;
13+ use crate :: webhooks:: WebhookConfig ;
1414
1515#[ cfg( feature = "alerting" ) ]
1616use crate :: alerting:: AlertingConfig ;
@@ -86,29 +86,90 @@ mod duration_secs {
8686 }
8787}
8888
89- /// Module for serializing UUID as string for TOML compatibility
90- mod uuid_string {
89+ /// Module for serializing chrono::Duration as human-readable strings (in days)
90+ mod chrono_duration_days {
91+ use chrono:: Duration ;
9192 use serde:: { Deserialize , Deserializer , Serializer } ;
92- use uuid:: Uuid ;
9393
94- pub fn serialize < S > ( uuid : & Uuid , serializer : S ) -> Result < S :: Ok , S :: Error >
94+ pub fn serialize < S > ( duration : & Duration , serializer : S ) -> Result < S :: Ok , S :: Error >
9595 where
9696 S : Serializer ,
9797 {
98- serializer. serialize_str ( & uuid. to_string ( ) )
98+ let days = duration. num_days ( ) ;
99+ if days == 0 {
100+ serializer. serialize_str ( "0d" )
101+ } else {
102+ serializer. serialize_str ( & format ! ( "{}d" , days) )
103+ }
99104 }
100105
101- pub fn deserialize < ' de , D > ( deserializer : D ) -> Result < Uuid , D :: Error >
106+ pub fn deserialize < ' de , D > ( deserializer : D ) -> Result < Duration , D :: Error >
102107 where
103108 D : Deserializer < ' de > ,
104109 {
105110 use serde:: de:: Error ;
111+
106112 let s = String :: deserialize ( deserializer) ?;
107- Uuid :: parse_str ( & s) . map_err ( D :: Error :: custom)
113+ parse_chrono_duration ( & s) . map_err ( D :: Error :: custom)
114+ }
115+
116+ /// Parse a duration string like "30d", "7d", etc.
117+ pub fn parse_chrono_duration ( s : & str ) -> Result < Duration , String > {
118+ let s = s. trim ( ) ;
119+
120+ // Handle just numbers (assume days)
121+ if let Ok ( days) = s. parse :: < i64 > ( ) {
122+ return Ok ( Duration :: days ( days) ) ;
123+ }
124+
125+ // Handle suffixed durations
126+ if s. len ( ) < 2 {
127+ return Err ( format ! ( "Invalid duration format: {}" , s) ) ;
128+ }
129+
130+ let ( num_str, suffix) = s. split_at ( s. len ( ) - 1 ) ;
131+ let num: i64 = num_str
132+ . parse ( )
133+ . map_err ( |_| format ! ( "Invalid number in duration: {}" , num_str) ) ?;
134+
135+ match suffix {
136+ "d" => Ok ( Duration :: days ( num) ) ,
137+ _ => Err ( format ! (
138+ "Invalid duration suffix: {}. Use d for days" ,
139+ suffix
140+ ) ) ,
141+ }
108142 }
109143}
110144
111- use uuid:: Uuid ;
145+ /// Module for serializing Option<chrono::Duration> as human-readable strings (in days)
146+ mod chrono_duration_days_option {
147+ use chrono:: Duration ;
148+ use serde:: { Deserialize , Deserializer , Serializer } ;
149+
150+ pub fn serialize < S > ( duration : & Option < Duration > , serializer : S ) -> Result < S :: Ok , S :: Error >
151+ where
152+ S : Serializer ,
153+ {
154+ match duration {
155+ Some ( d) => super :: chrono_duration_days:: serialize ( d, serializer) ,
156+ None => serializer. serialize_none ( ) ,
157+ }
158+ }
159+
160+ pub fn deserialize < ' de , D > ( deserializer : D ) -> Result < Option < Duration > , D :: Error >
161+ where
162+ D : Deserializer < ' de > ,
163+ {
164+ let opt: Option < String > = Option :: deserialize ( deserializer) ?;
165+ match opt {
166+ Some ( s) => super :: chrono_duration_days:: parse_chrono_duration ( & s)
167+ . map ( Some )
168+ . map_err ( serde:: de:: Error :: custom) ,
169+ None => Ok ( None ) ,
170+ }
171+ }
172+ }
112173
113174/// Main configuration for the Hammerwork job queue system.
114175///
@@ -443,9 +504,11 @@ pub struct ArchiveConfig {
443504 pub compression_level : u32 ,
444505
445506 /// Archive jobs older than this duration
507+ #[ serde( with = "chrono_duration_days" ) ]
446508 pub archive_after : Duration ,
447509
448510 /// Delete archived files older than this duration
511+ #[ serde( with = "chrono_duration_days_option" ) ]
449512 pub delete_after : Option < Duration > ,
450513
451514 /// Maximum archive file size in bytes
@@ -604,6 +667,7 @@ impl HammerworkConfig {
604667#[ cfg( test) ]
605668mod tests {
606669 use super :: * ;
670+ use crate :: streaming:: StreamBackend ;
607671 use tempfile:: tempdir;
608672
609673 #[ test]
@@ -648,6 +712,10 @@ mod tests {
648712 . with_worker_pool_size ( 6 ) ;
649713
650714 // Save config
715+ println ! ( "Testing TOML serialization..." ) ;
716+ let toml_result = toml:: to_string_pretty ( & config) ;
717+ println ! ( "TOML result: {:?}" , toml_result) ;
718+
651719 config. save_to_file ( config_path. to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
652720
653721 // Load config
@@ -724,6 +792,10 @@ mod tests {
724792 r#"
725793[database]
726794url = "postgresql://localhost/test"
795+ pool_size = 10
796+ connection_timeout_secs = 30
797+ auto_migrate = false
798+ create_tables = true
727799
728800[worker]
729801pool_size = 4
@@ -732,42 +804,89 @@ job_timeout = "5m"
732804autoscaling_enabled = false
733805min_workers = 1
734806max_workers = 10
735- scale_up_threshold = 0.8
736- scale_down_threshold = 0.2
737- scale_check_interval = "30s"
738807
739808[worker.priority_weights]
740- background = 1
741- low = 2
742- normal = 5
743- high = 10
744- critical = 20
809+ strict_priority = false
810+ fairness_factor = 0.1
811+
812+ [worker.priority_weights.weights]
813+ Background = 1
814+ Low = 2
815+ Normal = 5
816+ High = 10
817+ Critical = 20
745818
746819[worker.retry_strategy]
747- max_attempts = 3
748- initial_delay = "1s"
749- max_delay = "60s"
750- backoff_multiplier = 2.0
820+ type = "Exponential"
821+ base_ms = 1000
822+ multiplier = 2.0
823+ max_delay_ms = 60000
751824
752825[events]
753- enabled = true
754- buffer_size = 1000
826+ max_buffer_size = 1000
827+ include_payload_default = false
828+ max_payload_size_bytes = 65536
829+ log_events = false
830+
831+ [webhooks]
832+ webhooks = []
833+
834+ [webhooks.global_settings]
835+ max_concurrent_deliveries = 100
836+ max_response_body_size = 65536
837+ log_deliveries = true
838+ user_agent = "hammerwork-webhooks/1.13.0"
755839
756840[streaming]
841+ streams = []
842+
843+ [streaming.global_settings]
844+ max_concurrent_processors = 50
845+ log_operations = true
846+ global_flush_interval_secs = 10
847+
848+ [alerting]
849+ targets = []
850+ enabled = true
851+
852+ [alerting.cooldown_period]
853+ secs = 300
854+ nanos = 0
855+
856+ [alerting.custom_thresholds]
857+
858+ [metrics]
859+ registry_name = "hammerwork"
860+ collect_histograms = true
861+ custom_gauges = []
862+ custom_histograms = []
863+ update_interval = 15
864+
865+ [metrics.custom_labels]
757866
758867[archive]
759868enabled = false
760- retention_days = 30
761- compression_enabled = false
869+ archive_directory = "./archives"
870+ compression_level = 6
871+ archive_after = "30d"
872+ delete_after = "365d"
873+ max_file_size_bytes = 104857600
874+ include_payloads = true
762875
763876[rate_limiting]
764877enabled = false
765- requests_per_second = 100
766- burst_size = 200
878+
879+ [rate_limiting.default_throttle]
880+ enabled = true
881+
882+ [rate_limiting.queue_throttles]
767883
768884[logging]
769885level = "info"
770886json_format = false
887+ include_location = false
888+ enable_tracing = false
889+ service_name = "hammerwork"
771890"# ,
772891 duration_str
773892 ) ;
0 commit comments