wurk 1.7.3 → 1.7.5
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 +4 -4
- data/README.md +14 -0
- data/lib/wurk/api/validation.rb +1 -2
- data/lib/wurk/stats.rb +3 -3
- data/lib/wurk/swarm.rb +37 -0
- data/lib/wurk/version.rb +1 -1
- data/vendor/assets/dashboard/wurk-manifest.json +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ac61be234c0359ccb0761df401c351021317cf2a5ae162e2329dcd94d7b8b4af
|
|
4
|
+
data.tar.gz: 00e7d69e0a3d440f1bf335ebbeeceb80b7e93ec1f82a6f48fcc189f54c4737ab
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bd52c4819554b5cad428d2514379005027aaa21cddf679ae89974edd12568075711e5dbc41b86da656f7df4a6b28ccde88cd421952002cd9966ec0e72b7841cd
|
|
7
|
+
data.tar.gz: 796f59f291295b5681a920cb5c9d04baa70fb416afc3246db55d1ebbd009f5a6f348d785b57c80b1dd9a07dc249771b67b3bb9203927e41becf0484cf27a6c74
|
data/README.md
CHANGED
|
@@ -29,6 +29,8 @@ Wurk is wire-compatible with Sidekiq — same Redis keys, same job JSON, same Ru
|
|
|
29
29
|
|
|
30
30
|
**On speed:** Wurk is not currently faster than stock Sidekiq — it runs at roughly 0.87×–1.02× depending on workload shape, with parity on CPU and I/O but still behind on framework overhead (noop) and boot time. Numbers, method, and the reproduction command are in [docs/benchmarks.md](docs/benchmarks.md); run them yourself with `rake bench:vs_sidekiq`.
|
|
31
31
|
|
|
32
|
+
**Also from us:** [Ultimate](https://github.com/developerz-ai/ultimate) — the AI-first full-stack framework, for a weekend pet project or the system a company runs on. What a whole stack looks like when the one writing the code is an agent, not a human: [`bunx create-ultimate myapp`](#also-from-developerzai-ultimate).
|
|
33
|
+
|
|
32
34
|
## Install
|
|
33
35
|
|
|
34
36
|
```ruby
|
|
@@ -299,6 +301,18 @@ Wurk is MIT and stays that way. If what you need is a commercial support contrac
|
|
|
299
301
|
|
|
300
302
|
Full walkthrough — config side-by-side, the Redis key/`sidekiq_options` mapping, known incompatibilities, and a one-page cutover checklist: **[docs/migrate-from-sidekiq.md](https://github.com/developerz-ai/wurk/blob/main/docs/migrate-from-sidekiq.md)**.
|
|
301
303
|
|
|
304
|
+
## Also from developerz.ai: Ultimate
|
|
305
|
+
|
|
306
|
+
**[Ultimate](https://github.com/developerz-ai/ultimate) — the AI-first full-stack framework.** Rails' opinions, Bun's speed, one command that means shippable. Wurk is what one AI-maintained *library* looks like; Ultimate is the whole stack built on the same bet — the best framework you can hand a coding agent, whether what you are building is a weekend pet project or the system a company runs on.
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
bunx create-ultimate myapp && cd myapp && x dev
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Every framework of the last fifteen years optimised for a human typing the code. Ultimate assumes an agent writes it, and that rewrites the defaults: **one way to do each thing**, so there is nothing to choose between; conventions that are **build errors**, so the compiler corrects the agent instead of a reviewer; errors carrying a stable code, a cause, and the exact command that fixes it, so a failure costs one round-trip; docs shipped in `node_modules` and `--json` on every command, so nothing reaches for a wiki. `x verify` is the whole contract — green means shippable.
|
|
313
|
+
|
|
314
|
+
TypeScript end to end, MIT, and as measured about its own claims as this file is: what is proven, what is not, and what it refuses to claim yet are all in [its README](https://github.com/developerz-ai/ultimate#readme).
|
|
315
|
+
|
|
302
316
|
## Contributing
|
|
303
317
|
|
|
304
318
|
Issues and pull requests are welcome — see **[CONTRIBUTING.md](https://github.com/developerz-ai/wurk/blob/main/CONTRIBUTING.md)** for the dev setup, test layers, and conventions, and **[SECURITY.md](https://github.com/developerz-ai/wurk/blob/main/SECURITY.md)** to report a vulnerability.
|
data/lib/wurk/api/validation.rb
CHANGED
|
@@ -94,13 +94,12 @@ module Wurk
|
|
|
94
94
|
# one without reopening this file. Baked into the literal rather than
|
|
95
95
|
# appended at load, so the parallel test runner never observes a
|
|
96
96
|
# half-built list.
|
|
97
|
-
# rubocop:disable Style/MutableConstant
|
|
97
|
+
# rubocop:disable-next Style/MutableConstant
|
|
98
98
|
JOB_KEYS = %w[
|
|
99
99
|
class args queue at retry jid backtrace tags dead
|
|
100
100
|
retry_for retry_queue expires_in track timeout deadline
|
|
101
101
|
encrypt unique_for unique_until collapse log_level locale wrapped
|
|
102
102
|
]
|
|
103
|
-
# rubocop:enable Style/MutableConstant
|
|
104
103
|
|
|
105
104
|
# `push_bulk`'s envelope keys, on top of the job keys it shares.
|
|
106
105
|
BULK_KEYS = %w[batch_size spread_interval].freeze
|
data/lib/wurk/stats.rb
CHANGED
|
@@ -116,9 +116,9 @@ module Wurk
|
|
|
116
116
|
# Single pipeline for the cheap counters. Eagerly invoked at initialize
|
|
117
117
|
# so callers can read many fields without paying per-method round trips.
|
|
118
118
|
FAST_QUERIES = [
|
|
119
|
-
['GET',
|
|
120
|
-
['GET',
|
|
121
|
-
['GET',
|
|
119
|
+
['GET', 'stat:processed'],
|
|
120
|
+
['GET', 'stat:failed'],
|
|
121
|
+
['GET', Keys::STAT_EXPIRED],
|
|
122
122
|
['ZCARD', Keys::SCHEDULE],
|
|
123
123
|
['ZCARD', Keys::RETRY],
|
|
124
124
|
['ZCARD', Keys::DEAD],
|
data/lib/wurk/swarm.rb
CHANGED
|
@@ -65,6 +65,25 @@ module Wurk
|
|
|
65
65
|
# them mid-tail, so its own wait always extends past theirs by this much.
|
|
66
66
|
SHUTDOWN_GRACE = 5
|
|
67
67
|
|
|
68
|
+
# How often the drain re-relays TERM to whatever is still in the child
|
|
69
|
+
# table. A child forked in the instant before the drain can miss the first
|
|
70
|
+
# one outright: from `Process.fork` returning in the child until ChildBoot
|
|
71
|
+
# resets the inherited traps, the PARENT's handler is what a TERM finds
|
|
72
|
+
# there, and it writes the signal into the parent's self-pipe (or, once
|
|
73
|
+
# `fork_child` has dropped that pipe, into nothing) instead of stopping the
|
|
74
|
+
# child. The child then boots clean, drains nothing, and `wait_for_children`
|
|
75
|
+
# burns its whole budget before `hard_kill_stragglers` SIGKILLs it — taking
|
|
76
|
+
# its in-flight jobs with it. The window is the `_fork` hook chain
|
|
77
|
+
# (ActiveSupport's ForkTracker and friends all run child-side before
|
|
78
|
+
# `Process.fork` returns), so it widens with load: measured 10.5s drains
|
|
79
|
+
# against a 2.6s baseline once that chain is slowed. No child-side fix can
|
|
80
|
+
# close it — the window precedes any code the child controls — so the
|
|
81
|
+
# supervisor repeats itself instead. Re-sending is safe: by the second pass
|
|
82
|
+
# the child owns its handler, TERM to a child already draining is a no-op,
|
|
83
|
+
# and the pids come from the child table, where an exited child is a zombie
|
|
84
|
+
# until reaped and so can never be a recycled pid.
|
|
85
|
+
RETERM_INTERVAL = 1.0
|
|
86
|
+
|
|
68
87
|
# USR2 is relayed (log reopen) — without a trap, a logrotate config that
|
|
69
88
|
# signals the master pid would hit USR2's default disposition and kill the
|
|
70
89
|
# whole swarm.
|
|
@@ -341,7 +360,20 @@ module Wurk
|
|
|
341
360
|
# stall signal delivery if the pipe fills. `exception: false` returns
|
|
342
361
|
# :wait_writable instead of raising when full (drop the coalescible
|
|
343
362
|
# duplicate); a closed pipe during shutdown is ignored too.
|
|
363
|
+
#
|
|
364
|
+
# The owner check is what keeps ONE child's signal from draining the whole
|
|
365
|
+
# fleet. A forked child inherits both this trap and the parent's live pipe,
|
|
366
|
+
# and `fork_child` cannot drop them until `Process.fork` RETURNS — the
|
|
367
|
+
# `_fork` hook chain runs child-side before that, so there is a window
|
|
368
|
+
# where an operator's `kill <child_pid>` writes TERM into the PARENT's
|
|
369
|
+
# supervise loop and drains every sibling. Measured: with that chain slowed
|
|
370
|
+
# the way a loaded box does, TERMing a single child killed the supervisor
|
|
371
|
+
# and all of it. Comparing pids instead closes it with no window at all —
|
|
372
|
+
# the inherited trap is inert in the child from its first instruction,
|
|
373
|
+
# because `@owner_pid` was stamped before the fork.
|
|
344
374
|
def emit_signal(sig)
|
|
375
|
+
return unless owner?
|
|
376
|
+
|
|
345
377
|
@signal_write&.write_nonblock("#{sig}\n", exception: false)
|
|
346
378
|
rescue ::IOError, ::Errno::EPIPE, ::Errno::EBADF
|
|
347
379
|
nil
|
|
@@ -503,8 +535,13 @@ module Wurk
|
|
|
503
535
|
|
|
504
536
|
def wait_for_children(timeout)
|
|
505
537
|
deadline = monotonic + timeout
|
|
538
|
+
reterm_at = monotonic + RETERM_INTERVAL
|
|
506
539
|
while monotonic < deadline && any_children?
|
|
507
540
|
reap_children
|
|
541
|
+
if monotonic >= reterm_at
|
|
542
|
+
relay_signal('TERM')
|
|
543
|
+
reterm_at = monotonic + RETERM_INTERVAL
|
|
544
|
+
end
|
|
508
545
|
sleep 0.1
|
|
509
546
|
end
|
|
510
547
|
end
|
data/lib/wurk/version.rb
CHANGED