batch_machines 0.1.4-arm64-darwin
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 +7 -0
- data/CHANGELOG.md +29 -0
- data/LICENSE.txt +21 -0
- data/README.md +219 -0
- data/ext/batch_machines_native/core/CHANGELOG.md +29 -0
- data/ext/batch_machines_native/core/README.md +21 -0
- data/ext/batch_machines_native/extconf.rb +2 -0
- data/lib/batch_machines/version.rb +4 -0
- data/lib/batch_machines.rb +3 -0
- data/lib/batch_machines_native/batch_machines_native.bundle +0 -0
- data/sig/batch_machines.rbs +13 -0
- metadata +61 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b025f47eeb70434a02fd8e60cb54e40fd85d896ee7aa9b0d339a85431a065ee9
|
|
4
|
+
data.tar.gz: ab4add0214d8f2e8f2ad2395ea3c23d698e864f1b3c938fc77f2502185bd7e72
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: d7ad31e137d1522835281ae35105b9fa7b2e1669e1e1f3fe432b5b7d73f017ee341f051796ea620f6d4f1a61e5317ea5a0dbe030110d3342042fe9b1ab83bbcb
|
|
7
|
+
data.tar.gz: 2c80d8c18535ae0ea8e40b9b797e5fd905733164df4f180fab201057e58f7fb25d4033713d67e80225c48059f8855f5be2326ff2e522dcfce62d94786d072c20
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.1.4](https://github.com/seuros/batch_machines/compare/batch_machines/v0.1.3...batch_machines/v0.1.4) (2026-11-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* expose the pending deadline and weighted pushes ([9044fa3](https://github.com/seuros/batch_machines/commit/9044fa323859bcd6fb6cf9a7b5c884bf503fedc4))
|
|
9
|
+
|
|
10
|
+
## [0.1.3](https://github.com/seuros/batch_machines/compare/batch_machines/v0.1.2...batch_machines/v0.1.3) (2026-11-06)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* crates.io keywords and categories for the core ([b150571](https://github.com/seuros/batch_machines/commit/b150571563871f7af013b716402aa169688deaf2))
|
|
16
|
+
|
|
17
|
+
## [0.1.2](https://github.com/seuros/batch_machines/compare/batch_machines/v0.1.1...batch_machines/v0.1.2) (2026-11-06)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* keep test sources out of the packaged gem and crate ([2287c10](https://github.com/seuros/batch_machines/commit/2287c1089fefd9154740078a6977598f47033d0e))
|
|
23
|
+
|
|
24
|
+
## [0.1.1](https://github.com/seuros/batch_machines/compare/batch_machines-v0.1.0...batch_machines/v0.1.1) (2026-11-06)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
* initial extraction ([da62e4b](https://github.com/seuros/batch_machines/commit/da62e4bb16f3d1eaecc93ebf2a739f86fcfee932))
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Abdelkader Boudih
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# BatchMachines
|
|
2
|
+
|
|
3
|
+
> Fewer launches, fuller holds, and nobody left sitting on the pad. 🚚
|
|
4
|
+
|
|
5
|
+
A batching policy for Ruby. You tell it how big a batch may get and how long the oldest item may wait. Every time something arrives you `push` the clock, and it tells you whether to keep buffering or send now. On your timer you `poll`, and it tells you if the oldest item has waited long enough. When you've sent, you `flush`. It never sees your payloads. It only ever answers one question: is now the time?
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
gem 'batch_machines'
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
# Up to 500 rows per insert, and no row waits longer than 50ms.
|
|
15
|
+
batch = BatchMachines::Batch.new(500, 50_000_000)
|
|
16
|
+
rows = []
|
|
17
|
+
|
|
18
|
+
def ingest(batch, rows, row)
|
|
19
|
+
rows << row
|
|
20
|
+
case batch.push(now_ns)
|
|
21
|
+
when 'size', 'deadline' then insert_all(batch, rows)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def tick(batch, rows)
|
|
26
|
+
insert_all(batch, rows) if batch.poll(now_ns)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def insert_all(batch, rows)
|
|
30
|
+
Row.insert_all(rows)
|
|
31
|
+
rows.clear
|
|
32
|
+
batch.flush(now_ns)
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Time is Integer nanoseconds from a monotonic clock. `now_ns` is whatever you use for that, such as `Process.clock_gettime(Process::CLOCK_MONOTONIC, :nanosecond)`.
|
|
37
|
+
|
|
38
|
+
## A Message to the Resistance
|
|
39
|
+
|
|
40
|
+
So the event stream got busy and you were doing one INSERT per event. The database said no. You switched to batches of 500, and throughput went up tenfold. Then support opened a ticket: the last 37 events of every day show up the next morning, because 37 is less than 500 and nothing ever told them to go.
|
|
41
|
+
|
|
42
|
+
You added a timer. Now there's a batch size *and* a deadline, and a ticket about which one wins when both fire in the same tick, and another about the deadline resetting every time an item arrives so a steady trickle never flushes at all.
|
|
43
|
+
|
|
44
|
+
This is Nagle's problem from 1984 with the names changed. Group small things into bigger things, but never make the first small thing wait forever. The bookkeeping for that is three numbers: how many are waiting, how many you want before sending, and when the oldest one arrived. This gem keeps those three numbers and makes the call. The sending is still yours.
|
|
45
|
+
|
|
46
|
+
## Chapter 1: Stardate 2025.186, the AMS Nagle
|
|
47
|
+
|
|
48
|
+
> **AMS Nagle**, NCC-4202, *Nagle*-class cargo consolidator.
|
|
49
|
+
> Fewer launches. Fuller holds. No forgotten departure deadline.
|
|
50
|
+
|
|
51
|
+
The consolidator doesn't fly. It watches the loading bay. Every pod that rolls in is logged, and the moment the hold reaches target size, or the first pod has sat on the deck for its full wait, the launch order goes out. One launch per pod burns the convoy's fuel. One pod waiting a week burns the mission.
|
|
52
|
+
|
|
53
|
+
Somewhere in the bay, a loading officer proposes:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
def enqueue(row)
|
|
57
|
+
buffer << row
|
|
58
|
+
flush_all if buffer.size >= 500
|
|
59
|
+
end
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
"That," says the consolidator, "is how thirty-seven pods spend the night on the deck."
|
|
63
|
+
|
|
64
|
+
## The Flight Plan
|
|
65
|
+
|
|
66
|
+
Three things can be true of the hold: it has room and no reason to launch, it has reached its target, or the first pod has waited too long. Deadline beats size when both are true.
|
|
67
|
+
|
|
68
|
+
```mermaid
|
|
69
|
+
stateDiagram-v2
|
|
70
|
+
[*] --> empty
|
|
71
|
+
empty --> buffering: push, buffered (oldest timestamp set)
|
|
72
|
+
buffering --> buffering: push, buffered
|
|
73
|
+
buffering --> size_ready: push or poll, pending >= target
|
|
74
|
+
buffering --> deadline_ready: push or poll, oldest waited max_wait
|
|
75
|
+
size_ready --> deadline_ready: oldest waited max_wait
|
|
76
|
+
size_ready --> size_ready: push accepted (until capacity, then full)
|
|
77
|
+
size_ready --> empty: flush
|
|
78
|
+
deadline_ready --> empty: flush
|
|
79
|
+
buffering --> empty: flush
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
And a slow evening, with a trickle that never reaches 500:
|
|
83
|
+
|
|
84
|
+
```mermaid
|
|
85
|
+
sequenceDiagram
|
|
86
|
+
participant App
|
|
87
|
+
participant Batch
|
|
88
|
+
participant DB
|
|
89
|
+
|
|
90
|
+
App->>Batch: push(t=0ms)
|
|
91
|
+
Batch-->>App: buffered
|
|
92
|
+
App->>Batch: push(t=20ms)
|
|
93
|
+
Batch-->>App: buffered
|
|
94
|
+
App->>Batch: push(t=45ms)
|
|
95
|
+
Batch-->>App: buffered
|
|
96
|
+
Note over Batch: oldest arrived at 0ms, max wait 50ms
|
|
97
|
+
|
|
98
|
+
App->>Batch: poll(t=50ms)
|
|
99
|
+
Batch-->>App: deadline
|
|
100
|
+
App->>DB: INSERT 3 rows
|
|
101
|
+
App->>Batch: flush(t=51ms)
|
|
102
|
+
Batch-->>App: 3
|
|
103
|
+
Note over Batch: hold empty, no deadline pending
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## How the Hold Works
|
|
107
|
+
|
|
108
|
+
### Push
|
|
109
|
+
|
|
110
|
+
Every arrival is a `push` with the current time. The return value is a String telling you what to do.
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
batch = BatchMachines::Batch.new(2, 10)
|
|
114
|
+
|
|
115
|
+
batch.push(1) # => "buffered" room left, no reason to send
|
|
116
|
+
batch.push(2) # => "size" target reached, send now
|
|
117
|
+
batch.push(3) # => "full" capacity reached, this one was NOT accepted
|
|
118
|
+
batch.pending # => 2
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`"buffered"`, `"size"`, and `"deadline"` all mean the item was counted. `"full"` means it wasn't, and you need to flush before it can be. Keep your own list of payloads alongside, and only append when the push was accepted.
|
|
122
|
+
|
|
123
|
+
### Poll
|
|
124
|
+
|
|
125
|
+
Nothing arrives, time passes. `poll` asks the same question without adding anything. It answers `nil` when there's nothing to do.
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
batch = BatchMachines::Batch.new(100, 50_000_000)
|
|
129
|
+
batch.push(1_000)
|
|
130
|
+
batch.push(40_000_000)
|
|
131
|
+
|
|
132
|
+
batch.poll(50_000_999) # => nil oldest has waited 49.999999ms
|
|
133
|
+
batch.poll(50_001_000) # => "deadline" oldest has waited 50ms
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
The deadline belongs to the oldest item and never moves. A new arrival doesn't push it back, and neither does changing the target.
|
|
137
|
+
|
|
138
|
+
### Flush
|
|
139
|
+
|
|
140
|
+
When you've sent, say so. `flush` returns how many were waiting and empties the hold.
|
|
141
|
+
|
|
142
|
+
```ruby
|
|
143
|
+
batch.flush(50_001_000) # => 2
|
|
144
|
+
batch.flush(50_001_000) # => 0
|
|
145
|
+
batch.poll(60_000_000) # => nil
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Flushing an empty hold is fine and returns zero.
|
|
149
|
+
|
|
150
|
+
### Deadline wins
|
|
151
|
+
|
|
152
|
+
When an arrival both fills the target and lands at the deadline, you hear about the deadline. The older reason takes precedence.
|
|
153
|
+
|
|
154
|
+
```ruby
|
|
155
|
+
batch = BatchMachines::Batch.new(2, 10)
|
|
156
|
+
batch.push(0) # => "buffered"
|
|
157
|
+
batch.push(10) # => "deadline"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Adapting the target
|
|
161
|
+
|
|
162
|
+
The target size starts at capacity. If you'd rather it follow conditions downstream, such as insert latency, feed `adapt` an error signal and it moves the target for you, clamped to `1..capacity`. Out of the box it's a proportional controller with gain 1, so the target simply follows the number you give it. The second argument is how much time passed since the last call, in nanoseconds.
|
|
163
|
+
|
|
164
|
+
```ruby
|
|
165
|
+
batch = BatchMachines::Batch.new(100, 50_000_000)
|
|
166
|
+
batch.target # => 100
|
|
167
|
+
|
|
168
|
+
batch.adapt(10, 1_000_000_000) # => 10
|
|
169
|
+
batch.adapt(-3, 1_000_000_000) # => 1 never below one
|
|
170
|
+
batch.adapt(1000, 1_000_000_000) # => 100 never above capacity
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Need memory? `configure_pid(p, i, d)` sets the gains. With only an integral gain the target climbs a little more each call:
|
|
174
|
+
|
|
175
|
+
```ruby
|
|
176
|
+
batch = BatchMachines::Batch.new(100, 10)
|
|
177
|
+
batch.configure_pid(0, 1.0, 0)
|
|
178
|
+
|
|
179
|
+
batch.adapt(5.0, 1_000_000_000) # => 5
|
|
180
|
+
batch.adapt(5.0, 1_000_000_000) # => 10
|
|
181
|
+
batch.adapt(5.0, 1_000_000_000) # => 15
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Lowering the target doesn't drop anything already in the hold. Items past the target still count, and the next push or poll says `"size"` until you flush.
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
batch = BatchMachines::Batch.new(5, 10)
|
|
188
|
+
batch.push(0)
|
|
189
|
+
batch.adapt(2.0, 1_000_000_000) # => 2
|
|
190
|
+
batch.push(1) # => "size"
|
|
191
|
+
batch.push(2) # => "size" accepted, still under capacity 5
|
|
192
|
+
batch.pending # => 3
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## The Rules of the Consolidator
|
|
196
|
+
|
|
197
|
+
- **Capacity is an Integer** in `1...2**32`, and `max_wait_ns` is a positive Integer. Zero for either raises `ArgumentError`.
|
|
198
|
+
- **Time is unsigned 64-bit Integer nanoseconds.** Floats and strings raise `TypeError`, negative or overflow raises `RangeError`.
|
|
199
|
+
- **Time only moves forward.** A `push` with an earlier clock than the last one returns `"rejected"` and counts nothing. `poll` and `flush` with an earlier clock return `nil` and change nothing.
|
|
200
|
+
- **Gains are finite and non-negative.** Infinite, NaN, or negative gains raise `ArgumentError`. An error of infinity or NaN raises too, and `adapt` with zero elapsed raises.
|
|
201
|
+
- **A blown-up controller returns `nil`** and leaves the target where it was, rather than handing you a nonsense size.
|
|
202
|
+
- **Frozen means frozen.** `freeze` the batch and `push`, `poll`, `flush`, `adapt`, and `configure_pid` all raise `FrozenError`.
|
|
203
|
+
|
|
204
|
+
## What You Think You're Doing vs Reality
|
|
205
|
+
|
|
206
|
+
### You Think: "Batch of 500 or 50ms, whichever comes first. Easy."
|
|
207
|
+
### Reality: Whichever comes first, measured from when?
|
|
208
|
+
|
|
209
|
+
Measured from the newest item and a steady trickle never flushes. Measured from the last flush and the first item after a quiet hour waits the full 50ms plus however long the hour was. Measured from the oldest item, with the deadline pinned the moment it lands, and everything behaves. That last one is the only correct answer and it's the only one this gem knows how to give.
|
|
210
|
+
|
|
211
|
+
## What's Yours
|
|
212
|
+
|
|
213
|
+
The batch counts. It doesn't hold your rows, doesn't run a timer, and doesn't call the database. You keep the payloads in a list next to it, you call `poll` from whatever tick you already have, and you call `flush` after the send actually succeeded, not before. If the send fails, don't flush. The hold still knows how many are waiting and when the oldest arrived.
|
|
214
|
+
|
|
215
|
+
## License
|
|
216
|
+
|
|
217
|
+
MIT License. See [LICENSE.txt](LICENSE.txt) for details.
|
|
218
|
+
|
|
219
|
+
**Remember: The last thirty-seven events of the day are still events. Someone has to tell them to go.**
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.3.0](https://github.com/seuros/batch_machines/compare/batch-machines-v0.2.2...batch-machines-v0.3.0) (2026-11-06)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* expose the pending deadline and weighted pushes ([9044fa3](https://github.com/seuros/batch_machines/commit/9044fa323859bcd6fb6cf9a7b5c884bf503fedc4))
|
|
9
|
+
|
|
10
|
+
## [0.2.2](https://github.com/seuros/batch_machines/compare/batch-machines-v0.2.1...batch-machines-v0.2.2) (2026-11-06)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* crates.io keywords and categories for the core ([b150571](https://github.com/seuros/batch_machines/commit/b150571563871f7af013b716402aa169688deaf2))
|
|
16
|
+
|
|
17
|
+
## [0.2.1](https://github.com/seuros/batch_machines/compare/batch-machines-v0.2.0...batch-machines-v0.2.1) (2026-11-06)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Bug Fixes
|
|
21
|
+
|
|
22
|
+
* keep test sources out of the packaged gem and crate ([2287c10](https://github.com/seuros/batch_machines/commit/2287c1089fefd9154740078a6977598f47033d0e))
|
|
23
|
+
|
|
24
|
+
## [0.2.0](https://github.com/seuros/batch_machines/compare/batch-machines-v0.1.0...batch-machines-v0.2.0) (2026-11-06)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
* initial extraction ([da62e4b](https://github.com/seuros/batch_machines/commit/da62e4bb16f3d1eaecc93ebf2a739f86fcfee932))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# batch-machines
|
|
2
|
+
|
|
3
|
+
> **AMS Nagle**, NCC-4202, *Nagle*-class cargo consolidator.
|
|
4
|
+
|
|
5
|
+
Engine-room flight manual: fill the cargo hold without missing the launch window.
|
|
6
|
+
|
|
7
|
+
Allocation-free `no_std` size/deadline batch decisions. The first item establishes
|
|
8
|
+
a fixed maximum-wait deadline; later arrivals and target adaptation never move
|
|
9
|
+
that deadline. Poll with explicit monotonic time, or read `deadline()` and sleep
|
|
10
|
+
until it: it is the absolute time at which `poll` first reports `Deadline`, and
|
|
11
|
+
`None` while nothing is pending. A flush recommendation does not flush payloads:
|
|
12
|
+
the adapter must execute/acknowledge the flush, which also clears the deadline.
|
|
13
|
+
|
|
14
|
+
Capacity is a budget of cost units. `push` spends one unit per item;
|
|
15
|
+
`push_weighted` spends the item's cost, so a byte budget flushes at a byte
|
|
16
|
+
target. An item costing more than the capacity is never admitted. Flow credits
|
|
17
|
+
bound the pending cost. PID output can adapt the target cost, truncated toward
|
|
18
|
+
zero and clamped to `[1, capacity]`. Error definition, gains,
|
|
19
|
+
measurement, and downstream flush concurrency are caller policies. This cannot
|
|
20
|
+
guarantee an end-to-end latency budget if timers/execution are delayed. No I/O,
|
|
21
|
+
timer driver, payload storage, partial flush, or Ruby binding is included.
|
|
Binary file
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module BatchMachines
|
|
2
|
+
VERSION: String
|
|
3
|
+
class Batch
|
|
4
|
+
def self.new: (Integer capacity, Integer max_wait_ns) -> instance
|
|
5
|
+
def configure_pid: (Float | Integer p, Float | Integer i, Float | Integer d) -> nil
|
|
6
|
+
def push: (Integer now_ns) -> String
|
|
7
|
+
def poll: (Integer now_ns) -> String?
|
|
8
|
+
def flush: (Integer now_ns) -> Integer?
|
|
9
|
+
def adapt: (Float | Integer error, Integer elapsed_ns) -> Integer?
|
|
10
|
+
def pending: () -> Integer
|
|
11
|
+
def target: () -> Integer
|
|
12
|
+
end
|
|
13
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: batch_machines
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.4
|
|
5
|
+
platform: arm64-darwin
|
|
6
|
+
authors:
|
|
7
|
+
- Abdelkader Boudih
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-11-06 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Initial native batch policy model. Caller owns payloads and execution.
|
|
14
|
+
Local sibling Rust checkouts required.
|
|
15
|
+
email:
|
|
16
|
+
- oss@seuros.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- CHANGELOG.md
|
|
22
|
+
- LICENSE.txt
|
|
23
|
+
- README.md
|
|
24
|
+
- ext/batch_machines_native/core/CHANGELOG.md
|
|
25
|
+
- ext/batch_machines_native/core/README.md
|
|
26
|
+
- ext/batch_machines_native/extconf.rb
|
|
27
|
+
- lib/batch_machines.rb
|
|
28
|
+
- lib/batch_machines/version.rb
|
|
29
|
+
- lib/batch_machines_native/batch_machines_native.bundle
|
|
30
|
+
- sig/batch_machines.rbs
|
|
31
|
+
homepage: https://github.com/seuros/batch_machines
|
|
32
|
+
licenses:
|
|
33
|
+
- MIT
|
|
34
|
+
metadata:
|
|
35
|
+
source_code_uri: https://github.com/seuros/batch_machines
|
|
36
|
+
rubygems_mfa_required: 'true'
|
|
37
|
+
cargo_crate_name: batch_machines_native
|
|
38
|
+
cargo_manifest_path: ext/batch_machines_native/ffi/Cargo.toml
|
|
39
|
+
post_install_message:
|
|
40
|
+
rdoc_options: []
|
|
41
|
+
require_paths:
|
|
42
|
+
- lib
|
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '4.0'
|
|
48
|
+
- - "<"
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: 4.1.dev
|
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0'
|
|
56
|
+
requirements: []
|
|
57
|
+
rubygems_version: 3.5.23
|
|
58
|
+
signing_key:
|
|
59
|
+
specification_version: 4
|
|
60
|
+
summary: Native size/deadline batch decisions with PID adaptation
|
|
61
|
+
test_files: []
|