supervisor_machines 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bcf2434ae701ae257e80d7203631c5a771fe2f918fb30ccc654e7cfb8a4bdedd
4
- data.tar.gz: e49e4fb0b7b99f34a0e81ac06e68bc3b22244253a34877410130568a4303bd9d
3
+ metadata.gz: f36d17f94d2e12b476ab45bf7bf3d4e0f2ff0b7f936866fe110802dec8d7cb74
4
+ data.tar.gz: 9514f57779388f9574596178e9812b71873ae8a40630c91a98c821bad3f03347
5
5
  SHA512:
6
- metadata.gz: aba61a49c4e301984d91c9bd9e6c85da75672038ded38bb7a9d3ed26b661a1d16bf5a2befe4b5d58fdb47c1f5119e8050672feb1b2c1ba6504d800198a226260
7
- data.tar.gz: 2cfeba21ac509d76ae75018c8c8811f0d52a3f9462c234b26b1d451f7afcd35b45dcdc7a99bd21afe8f6e8b3880753f655929fc3cab8462dde9789fd7d97a679
6
+ metadata.gz: 3aeac1b644cc8ea8e9ec41748b44c9e541a8be0ac5287b73e6047aa598d146542a8e6a3312d96e07af93ab05bb5be483dcbe5110910897912578b77d248514d3
7
+ data.tar.gz: 4d8fd693df515ced5543be1a6e15a5b12ea1162deb27f9d71996aaf8cef1a805d93162b130fa88254dc771a6596b5c7f962dfa4cd682815dccdf532e4533480e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.3](https://github.com/seuros/supervisor_machines/compare/supervisor_machines/v0.1.2...supervisor_machines/v0.1.3) (2026-11-01)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * enable the rb-sys compiled fallback so new Rubies can build ([ef51e18](https://github.com/seuros/supervisor_machines/commit/ef51e18b3fe96522ce56ace91d93055e33996e78))
9
+ * raise the chrono_machines floor to 0.12.1 ([20b6538](https://github.com/seuros/supervisor_machines/commit/20b6538967c3e6bde705c8822d3a53ad6a07a1f6))
10
+
11
+ ## [0.1.2](https://github.com/seuros/supervisor_machines/compare/supervisor_machines/v0.1.1...supervisor_machines/v0.1.2) (2026-11-01)
12
+
13
+
14
+ ### Features
15
+
16
+ * back off granted restarts by recent restart count ([e7532e8](https://github.com/seuros/supervisor_machines/commit/e7532e8e98e43171c8d76f176161fdea50403a27))
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * a republished platform gem is skipped, not fatal ([39160e7](https://github.com/seuros/supervisor_machines/commit/39160e7e295d58500d846fb56d190eff6e803151))
22
+
3
23
  ## [0.1.1](https://github.com/seuros/supervisor_machines/compare/supervisor_machines-v0.1.0...supervisor_machines/v0.1.1) (2026-11-01)
4
24
 
5
25
 
data/Cargo.lock CHANGED
@@ -252,13 +252,14 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
252
252
 
253
253
  [[package]]
254
254
  name = "supervisor-machines"
255
- version = "0.2.0"
255
+ version = "0.3.0"
256
256
 
257
257
  [[package]]
258
258
  name = "supervisor_machines_native"
259
- version = "0.1.1"
259
+ version = "0.1.2"
260
260
  dependencies = [
261
261
  "magnus",
262
+ "rb-sys",
262
263
  "supervisor-machines",
263
264
  ]
264
265
 
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "supervisor-machines"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  edition.workspace = true
5
5
  rust-version.workspace = true
6
6
  authors = ["Abdelkader Boudih <oss@seuros.com>"]
@@ -97,6 +97,58 @@ impl<const CHILDREN: usize, const HISTORY: usize> Supervisor<CHILDREN, HISTORY>
97
97
  counted
98
98
  }
99
99
 
100
+ /// How long to hold off the restart just granted: `base_ns` doubled once
101
+ /// per restart already inside the window, capped at `ceiling_ns`.
102
+ ///
103
+ /// Neither OTP nor [`stopped`](Self::stopped) imposes a delay, so a
104
+ /// supervisor that restarts the moment a child dies spends its whole
105
+ /// intensity budget in the time it takes to fail that many times. For a
106
+ /// child that dies while being constructed that is well under a
107
+ /// millisecond, and the window the intensity was written for never gets to
108
+ /// mean anything. Waiting this long between the decision and the restart
109
+ /// spreads the budget back over that window.
110
+ ///
111
+ /// The count decays as the window slides, so a child that settles returns
112
+ /// to `base_ns` on its own. Jitter is the caller's to add.
113
+ ///
114
+ /// ```
115
+ /// use supervisor_machines::{Exit, Intensity, Policy, Strategy, Supervisor};
116
+ ///
117
+ /// const MS: u64 = 1_000_000;
118
+ ///
119
+ /// let mut tree: Supervisor<1, 8> = Supervisor::new(
120
+ /// Strategy::OneForOne,
121
+ /// Intensity::new(5, 60_000 * MS),
122
+ /// );
123
+ ///
124
+ /// // The first restart waits the base, each further one twice as long.
125
+ /// tree.stopped(0, Policy::Permanent, Exit::Abnormal, 0);
126
+ /// assert_eq!(tree.restart_delay_ns(100 * MS, 10_000 * MS, 0), 100 * MS);
127
+ ///
128
+ /// tree.stopped(0, Policy::Permanent, Exit::Abnormal, MS);
129
+ /// assert_eq!(tree.restart_delay_ns(100 * MS, 10_000 * MS, MS), 200 * MS);
130
+ ///
131
+ /// // Once the window has slid past them the delay is back to the base.
132
+ /// assert_eq!(
133
+ /// tree.restart_delay_ns(100 * MS, 10_000 * MS, 120_000 * MS),
134
+ /// 100 * MS,
135
+ /// );
136
+ /// ```
137
+ #[must_use]
138
+ pub const fn restart_delay_ns(&self, base_ns: u64, ceiling_ns: u64, now_ns: u64) -> u64 {
139
+ let mut delay = base_ns;
140
+ let mut doublings = self.recent_restarts(now_ns).saturating_sub(1);
141
+ while doublings > 0 && delay < ceiling_ns {
142
+ delay = delay.saturating_mul(2);
143
+ doublings -= 1;
144
+ }
145
+ if delay > ceiling_ns {
146
+ ceiling_ns
147
+ } else {
148
+ delay
149
+ }
150
+ }
151
+
100
152
  /// The children a failure at `index` takes with it under this strategy.
101
153
  #[must_use]
102
154
  pub const fn span(&self, index: usize) -> Span {
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "supervisor_machines_native"
3
- version = "0.1.1"
3
+ version = "0.1.2"
4
4
  edition.workspace = true
5
5
  rust-version.workspace = true
6
6
  authors = ["Abdelkader Boudih <oss@seuros.com>"]
@@ -17,3 +17,15 @@ workspace = true
17
17
  [dependencies]
18
18
  supervisor-machines = { workspace = true, features = ["std"] }
19
19
  magnus = { version = ">= 0.9.3", default-features = false, features = ["io"] }
20
+ # Nothing here calls rb-sys directly: this is the compiled fallback that
21
+ # implements the stable API for a Ruby rb-sys has no pre-generated bindings
22
+ # for, such as a preview. magnus asks for "stable-api" without it, and
23
+ # default-features = false drops the default that would have supplied it, so
24
+ # removing this line breaks the build on every future Ruby.
25
+ # Nothing here calls rb-sys directly: this is the compiled fallback that
26
+ # implements the stable API for a Ruby rb-sys ships no pre-generated bindings
27
+ # for, such as a preview. magnus asks for "stable-api" without it, and its
28
+ # default-features = false drops the default that would have supplied it, so
29
+ # dropping this line breaks the build on every Ruby newer than rb-sys.
30
+ rb-sys = { version = ">= 0.9.130", default-features = false, features = ["stable-api-compiled-fallback"] }
31
+
@@ -30,6 +30,7 @@ trait Decide: Send {
30
30
  fn strategy(&self) -> Strategy;
31
31
  fn terminated(&self) -> bool;
32
32
  fn recent_restarts(&self, now_ns: u64) -> u32;
33
+ fn restart_delay_ns(&self, base_ns: u64, ceiling_ns: u64, now_ns: u64) -> u64;
33
34
  fn stopped(&mut self, index: usize, policy: Policy, exit: Exit, now_ns: u64) -> Decision;
34
35
  }
35
36
 
@@ -54,6 +55,10 @@ impl<const CHILDREN: usize> Decide for Shape<CHILDREN> {
54
55
  self.0.recent_restarts(now_ns)
55
56
  }
56
57
 
58
+ fn restart_delay_ns(&self, base_ns: u64, ceiling_ns: u64, now_ns: u64) -> u64 {
59
+ self.0.restart_delay_ns(base_ns, ceiling_ns, now_ns)
60
+ }
61
+
57
62
  fn stopped(&mut self, index: usize, policy: Policy, exit: Exit, now_ns: u64) -> Decision {
58
63
  self.0.stopped(index, policy, exit, now_ns)
59
64
  }
@@ -164,6 +169,23 @@ impl Wrapper {
164
169
  self.0.borrow().recent_restarts(now_ns)
165
170
  }
166
171
 
172
+ /// How long to hold off a granted restart, backing off per restart already
173
+ /// inside the window.
174
+ fn restart_delay_ns(rb_self: &Self, args: &[Value]) -> Result<u64, Error> {
175
+ let args = scan_args::<(), (), (), (), RHash, ()>(args)?;
176
+ let (Whole(base_ns), Whole(ceiling_ns), Whole(now_ns)) =
177
+ get_kwargs::<_, (Whole<u64>, Whole<u64>, Whole<u64>), (), ()>(
178
+ args.keywords,
179
+ &["base_ns", "ceiling_ns", "now_ns"],
180
+ &[],
181
+ )?
182
+ .required;
183
+ Ok(rb_self
184
+ .0
185
+ .borrow()
186
+ .restart_delay_ns(base_ns, ceiling_ns, now_ns))
187
+ }
188
+
167
189
  fn inspect(ruby: &Ruby, rb_self: &Self) -> String {
168
190
  format!(
169
191
  "#<SupervisorMachines::Decider strategy={} children={} terminated={}>",
@@ -185,6 +207,7 @@ pub fn define(ruby: &Ruby, module: RModule) -> Result<(), Error> {
185
207
  class.define_method("strategy", method!(Wrapper::strategy, 0))?;
186
208
  class.define_method("terminated?", method!(Wrapper::terminated, 0))?;
187
209
  class.define_method("recent_restarts", method!(Wrapper::recent_restarts, 1))?;
210
+ class.define_method("restart_delay_ns", method!(Wrapper::restart_delay_ns, -1))?;
188
211
  class.define_method("inspect", method!(Wrapper::inspect, 0))?;
189
212
  Ok(())
190
213
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SupervisorMachines
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: supervisor_machines
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Abdelkader Boudih
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '0.11'
18
+ version: 0.12.1
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '0.11'
25
+ version: 0.12.1
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: deadline_machines
28
28
  requirement: !ruby/object:Gem::Requirement