zizq 0.1.0

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.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +94 -0
  4. data/bin/profile-worker +145 -0
  5. data/bin/zizq-worker +174 -0
  6. data/lib/active_job/queue_adapters/zizq_adapter.rb +109 -0
  7. data/lib/zizq/ack_processor.rb +132 -0
  8. data/lib/zizq/active_job_config.rb +122 -0
  9. data/lib/zizq/backoff.rb +50 -0
  10. data/lib/zizq/bulk_enqueue.rb +87 -0
  11. data/lib/zizq/client.rb +982 -0
  12. data/lib/zizq/configuration.rb +164 -0
  13. data/lib/zizq/enqueue_request.rb +178 -0
  14. data/lib/zizq/enqueue_with.rb +109 -0
  15. data/lib/zizq/error.rb +43 -0
  16. data/lib/zizq/job.rb +188 -0
  17. data/lib/zizq/job_config.rb +244 -0
  18. data/lib/zizq/lifecycle.rb +58 -0
  19. data/lib/zizq/middleware.rb +79 -0
  20. data/lib/zizq/query.rb +566 -0
  21. data/lib/zizq/resources/error_enumerator.rb +241 -0
  22. data/lib/zizq/resources/error_page.rb +19 -0
  23. data/lib/zizq/resources/error_record.rb +19 -0
  24. data/lib/zizq/resources/job.rb +124 -0
  25. data/lib/zizq/resources/job_page.rb +57 -0
  26. data/lib/zizq/resources/page.rb +77 -0
  27. data/lib/zizq/resources/resource.rb +45 -0
  28. data/lib/zizq/resources.rb +16 -0
  29. data/lib/zizq/version.rb +9 -0
  30. data/lib/zizq/worker.rb +467 -0
  31. data/lib/zizq.rb +269 -0
  32. data/sig/generated/zizq/ack_processor.rbs +73 -0
  33. data/sig/generated/zizq/active_job_config.rbs +74 -0
  34. data/sig/generated/zizq/backoff.rbs +34 -0
  35. data/sig/generated/zizq/bulk_enqueue.rbs +72 -0
  36. data/sig/generated/zizq/client.rbs +419 -0
  37. data/sig/generated/zizq/configuration.rbs +95 -0
  38. data/sig/generated/zizq/enqueue_request.rbs +94 -0
  39. data/sig/generated/zizq/enqueue_with.rbs +88 -0
  40. data/sig/generated/zizq/error.rbs +41 -0
  41. data/sig/generated/zizq/job.rbs +136 -0
  42. data/sig/generated/zizq/job_config.rbs +150 -0
  43. data/sig/generated/zizq/lifecycle.rbs +34 -0
  44. data/sig/generated/zizq/middleware.rbs +50 -0
  45. data/sig/generated/zizq/query.rbs +327 -0
  46. data/sig/generated/zizq/resources/error_enumerator.rbs +148 -0
  47. data/sig/generated/zizq/resources/error_page.rbs +13 -0
  48. data/sig/generated/zizq/resources/error_record.rbs +20 -0
  49. data/sig/generated/zizq/resources/job.rbs +89 -0
  50. data/sig/generated/zizq/resources/job_page.rbs +33 -0
  51. data/sig/generated/zizq/resources/page.rbs +47 -0
  52. data/sig/generated/zizq/resources/resource.rbs +26 -0
  53. data/sig/generated/zizq/version.rbs +5 -0
  54. data/sig/generated/zizq/worker.rbs +152 -0
  55. data/sig/generated/zizq.rbs +180 -0
  56. data/sig/zizq.rbs +111 -0
  57. metadata +134 -0
@@ -0,0 +1,41 @@
1
+ # Generated from lib/zizq/error.rb with RBS::Inline
2
+
3
+ module Zizq
4
+ # Base error class for all Zizq errors.
5
+ class Error < StandardError
6
+ end
7
+
8
+ # Network-level failure (connection refused, DNS, timeout etc).
9
+ class ConnectionError < Error
10
+ end
11
+
12
+ # HTTP error — the server returned a non-success status code.
13
+ # Carries the status code and parsed body.
14
+ class ResponseError < Error
15
+ # The HTTP response status from the Zizq server.
16
+ attr_reader status: Integer
17
+
18
+ # The decoded body of the error response.
19
+ attr_reader body: Hash[String, untyped]?
20
+
21
+ # Create a new ResponseError with the given error message, response status
22
+ # and decoded response body.
23
+ def initialize: (untyped message, status: untyped, ?body: untyped) -> untyped
24
+ end
25
+
26
+ # 4xx client error.
27
+ class ClientError < ResponseError
28
+ end
29
+
30
+ # 404 specifically — job not found, etc.
31
+ class NotFoundError < ClientError
32
+ end
33
+
34
+ # 5xx server error.
35
+ class ServerError < ResponseError
36
+ end
37
+
38
+ # Streaming take-jobs connection interrupted.
39
+ class StreamError < Error
40
+ end
41
+ end
@@ -0,0 +1,136 @@
1
+ # Generated from lib/zizq/job.rb with RBS::Inline
2
+
3
+ module Zizq
4
+ # Mixin which all valid job classes must include.
5
+ #
6
+ # This module must be included in a class to make it a valid Zizq job. The
7
+ # class name becomes the job type, and the worker resolves types back to
8
+ # classes via `Object.const_get` (which naturally triggers any autoload
9
+ # logic).
10
+ #
11
+ # class SendEmailJob
12
+ # include Zizq::Job
13
+ #
14
+ # zizq_queue "emails" # optional, defaults to "default"
15
+ #
16
+ # def perform(user_id, template:)
17
+ # puts "Sending #{template} email to user #{user_id}"
18
+ # end
19
+ # end
20
+ #
21
+ # The job can be configured through class methods to set the queue, priority
22
+ # etc. Classes can also override `::zizq_enqueue_options` to implement
23
+ # dynamically configured jobs based on their arguments.
24
+ module Job
25
+ def self.included: (untyped base) -> untyped
26
+
27
+ # Default dispatcher for Zizq jobs.
28
+ #
29
+ # Resolves the job class from the type string, deserializes the
30
+ # payload, and calls `#perform`. Any object that responds to
31
+ # `#call(job)` can replace this as a custom dispatcher via
32
+ # `Zizq.configure { |c| c.dispatcher = MyDispatcher.new }`.
33
+ #
34
+ # The contract is simple: return normally → ack, raise → nack.
35
+ #
36
+ # @rbs job: Resources::Job
37
+ # @rbs return: void
38
+ def self.call: (Resources::Job job) -> void
39
+
40
+ module ClassMethods
41
+ include JobConfig
42
+
43
+ # Serialize positional and keyword arguments for the `#perform` method
44
+ # into a payload hash suitable for sending to the server.
45
+ #
46
+ # The result must be a JSON encodable Hash.
47
+ #
48
+ # The default implementation generates a hash of the form:
49
+ #
50
+ # { "args" => [ 42, "Hello" ], "kwargs" => { "template": "example" } }
51
+ #
52
+ # If you override this method you almost certainly need to override
53
+ # `::zizq_deserialize`, `::zizq_payload_filter` and
54
+ # `::zizq_payload_subset_filter` too.
55
+ #
56
+ # Any failure to deserialize the arguments will cause the job to fail and
57
+ # backoff according to the backoff policy.
58
+ def zizq_serialize: (*untyped args, **untyped kwargs) -> untyped
59
+
60
+ # Deserialize a payload hash back into positional and keyword arguments.
61
+ #
62
+ # The payload is a JSON decoded Hash.
63
+ #
64
+ # The default implementation receives a Hash of the form:
65
+ #
66
+ # { "args" => [ 42, "Hello" ], "kwargs" => { "template": "example" } }
67
+ #
68
+ # And returns an array for `args` and `kwargs` of the form:
69
+ #
70
+ # [ [ 42, "Hello" ], {template: "example"} ]
71
+ #
72
+ # Because the default implementation uses a JSON decoded Hash, any symbol
73
+ # keys that were present at enqueue-time will be string keys after
74
+ # decoding.
75
+ #
76
+ # Any failure to deserialize the arguments will cause the job to fail and
77
+ # backoff according to the backoff policy.
78
+ def zizq_deserialize: (untyped payload) -> untyped
79
+
80
+ # Generate a jq expression that exactly matches payloads with the given
81
+ # arguments.
82
+ #
83
+ # This is used for filtering in Zizq::Query.
84
+ #
85
+ # Generates an expression of the form:
86
+ #
87
+ # . == {"args":["a","b","c"],"kwargs":{"example":true,"other":false}}
88
+ def zizq_payload_filter: (*untyped args, **untyped kwargs) -> untyped
89
+
90
+ # Generate a jq expression that matches jobs whose positional args
91
+ # start with the given values and whose kwargs contain the given
92
+ # key/value pairs.
93
+ #
94
+ # This is used for filtering in Zizq::Query.
95
+ #
96
+ # Generates expressions of the form:
97
+ #
98
+ # (.args[0:2] == ["a","b"]) and (.kwargs | contains({"example":true}))
99
+ def zizq_payload_subset_filter: (*untyped args, **untyped kwargs) -> untyped
100
+ end
101
+
102
+ # This is your job's main entrypoint when it is run by the worker.
103
+ #
104
+ # Override this method in your job class to define the work to perform.
105
+ # Declare any positional and keyword arguments your job needs.
106
+ #
107
+ # Strong recommendation: stick to keyword arguments because they are much
108
+ # easier to evolve over time in a backwards compatible way with any already
109
+ # enqueued jobs.
110
+ def perform: (*untyped args, **untyped kwargs) -> untyped
111
+
112
+ # The unique job ID assigned by the server.
113
+ def zizq_id: () -> untyped
114
+
115
+ # How many times this job has previously been attempted (0 on the first
116
+ # run, 1 on the second, etc...).
117
+ def zizq_attempts: () -> untyped
118
+
119
+ # The queue this job was dequeued from.
120
+ def zizq_queue: () -> untyped
121
+
122
+ # The priority this job was enqueued with.
123
+ def zizq_priority: () -> untyped
124
+
125
+ # Time at which this job was dequeued (fractional seconds since the Unix
126
+ # epoch). This can be converted to `Time` by using `Time.at(dequeued_at)`
127
+ # but that is intentionally left to the caller due to time zone
128
+ # considerations.
129
+ def zizq_dequeued_at: () -> untyped
130
+
131
+ # @api private
132
+ # Set by the worker before calling #perform. Receives the full
133
+ # Resources::Job object so all metadata is available through delegation.
134
+ def set_zizq_job: (untyped job) -> untyped
135
+ end
136
+ end
@@ -0,0 +1,150 @@
1
+ # Generated from lib/zizq/job_config.rb with RBS::Inline
2
+
3
+ module Zizq
4
+ # Shared class-level configuration DSL for Zizq job classes.
5
+ #
6
+ # This module provides the queue, priority, retry, backoff, retention,
7
+ # and uniqueness configuration methods. It is extended onto job classes
8
+ # by `Zizq::Job` and can also be used with ActiveJob via
9
+ # `Zizq::ActiveJobConfig`.
10
+ #
11
+ # Modules including this module must implement `zizq_serialize` and
12
+ # `zizq_deserialize` to define how job arguments are serialized for the API.
13
+ module JobConfig
14
+ # The class name where this is included (invisible to steep without this).
15
+ def name: () -> String?
16
+
17
+ # Serialize positional and keyword arguments into a JSON-serializable
18
+ # payload.
19
+ #
20
+ # Implemented by the including module.
21
+ def zizq_serialize: (*untyped args, **untyped kwargs) -> untyped
22
+
23
+ # Deserialize positional and keyword arguments from the serialized payload.
24
+ #
25
+ # Implemented by the including module.
26
+ def zizq_deserialize: (untyped payload) -> untyped
27
+
28
+ # Generate a jq expression that exactly matches payloads with the given
29
+ # arguments.
30
+ #
31
+ # Implemented by the including module.
32
+ def zizq_payload_filter: (*untyped args, **untyped kwargs) -> untyped
33
+
34
+ # Generate a jq expression that matches a subset of the given arguments.
35
+ #
36
+ # Implemented by the including module.
37
+ def zizq_payload_subset_filter: (*untyped args, **untyped kwargs) -> untyped
38
+
39
+ # Declare the default queue for this job class.
40
+ #
41
+ # If not called, defaults to "default". Jobs enqueued for this class will
42
+ # use the specified queue unless explicitly overridden during
43
+ # [`Zizq::enqueue`] or by overriding `::zizq_enqueue_options` on the job
44
+ # class.
45
+ def zizq_queue: (?untyped name) -> untyped
46
+
47
+ # Declare the default priority for this job class.
48
+ #
49
+ # If not called, defaults to the default priority on the Zizq server.
50
+ # Jobs enqueued for this class will use the specified priority unless
51
+ # explicitly overridden during [`Zizq::enqueue`] or by overriding
52
+ # `::zizq_enqueue_options` on the job class.
53
+ def zizq_priority: (?untyped priority) -> untyped
54
+
55
+ # Declare the default retry limit for this job class.
56
+ #
57
+ # The job may fail up to the number of times specified by the retry limit
58
+ # and will exponentially backoff. Once the retry limit is reached, the
59
+ # job is killed and becomes part of the dead set.
60
+ #
61
+ # If not configured, the server's default is used.
62
+ def zizq_retry_limit: (?untyped limit) -> untyped
63
+
64
+ # Declare the default backoff configuration for this job class.
65
+ #
66
+ # Times are specified in seconds (optionally fractional).
67
+ # In a Rails app `ActiveSupport::Duration` is supported too.
68
+ #
69
+ # All three parameters must be specified together and are used in the
70
+ # following exponential backoff formula:
71
+ #
72
+ # delay = base + attempts**exponent + rand(0.0..jitter)*attempts
73
+ #
74
+ # Example:
75
+ #
76
+ # zizq_backoff exponent: 4.0, base: 15, jitter: 30
77
+ #
78
+ # If not configured, the server's default backoff policy is used.
79
+ def zizq_backoff: (?exponent: untyped, ?base: untyped, ?jitter: untyped) -> untyped
80
+
81
+ # Declare the default retention configuration for this job class.
82
+ #
83
+ # Times are specified in seconds (optionally fractional).
84
+ # In a Rails app `ActiveSupport::Duration` is supported too.
85
+ #
86
+ # Both parameters are optional — only the ones provided will be sent
87
+ # to the server. Omitted values use the server's defaults.
88
+ #
89
+ # Example:
90
+ #
91
+ # zizq_retention completed: 0, dead: 7 * 86_400
92
+ #
93
+ # If not configured, the server's default is used.
94
+ def zizq_retention: (?completed: untyped, ?dead: untyped) -> untyped
95
+
96
+ # Declare uniqueness for this job class.
97
+ #
98
+ # Requires a pro license.
99
+ #
100
+ # When enabled, duplicate jobs with the same unique key are rejected
101
+ # at enqueue time. The optional scope controls how long the
102
+ # uniqueness guard lasts:
103
+ #
104
+ # :queued — unique while "scheduled" or "ready" (server default)
105
+ # :active — unique while "scheduled", "ready", or "in_flight"
106
+ # :exists — unique until the job is reaped by the server
107
+ #
108
+ # Examples:
109
+ #
110
+ # zizq_unique true # unique, server default scope
111
+ # zizq_unique true, scope: :active # unique while active
112
+ # zizq_unique false # disable (e.g. in a subclass)
113
+ def zizq_unique: (?untyped unique, ?scope: untyped) -> untyped
114
+
115
+ # Declare or read the uniqueness scope for this job class.
116
+ #
117
+ # Usually set via `zizq_unique true, scope: :active` but can also
118
+ # be set independently.
119
+ def zizq_unique_scope: (?untyped scope) -> untyped
120
+
121
+ # Compute the unique key for a job with the given arguments.
122
+ #
123
+ # The default implementation uses the class name and hashes the
124
+ # normalized serialized payload. Override this method to customize
125
+ # uniqueness — for example, to ignore certain arguments:
126
+ #
127
+ # def self.zizq_unique_key(user_id, template:)
128
+ # super(user_id) # unique per user, ignoring template
129
+ # end
130
+ def zizq_unique_key: (*untyped args, **untyped kwargs) -> untyped
131
+
132
+ # Build a `Zizq::EnqueueRequest` from the class-level job config.
133
+ #
134
+ # Subclasses can override this to implement dynamic logic such as
135
+ # priority based on arguments:
136
+ #
137
+ # def self.zizq_enqueue_request(user_id, template:)
138
+ # req = super
139
+ # req.priority = 0 if template == "urgent"
140
+ # req
141
+ # end
142
+ def zizq_enqueue_request: (*untyped args, **untyped kwargs) -> untyped
143
+
144
+ private
145
+
146
+ # Deep-sort all Hash keys so that serialization is deterministic
147
+ # regardless of insertion order or JSON library.
148
+ def normalize_payload: (untyped obj) -> untyped
149
+ end
150
+ end
@@ -0,0 +1,34 @@
1
+ # Generated from lib/zizq/lifecycle.rb with RBS::Inline
2
+
3
+ module Zizq
4
+ # Thread-safe state machine for coordinating worker shutdown.
5
+ #
6
+ # States:
7
+ # :running → normal operation
8
+ # :draining → stop accepting work, finish in-progress jobs
9
+ # :stopped → all work drained, safe to disconnect
10
+ #
11
+ # Transitions: running -> draining -> stopped (forward only).
12
+ #
13
+ # All transitions are signal-trap safe — they use only atomic symbol
14
+ # assignment and Queue#close for wakeups.
15
+ class Lifecycle
16
+ # @rbs return: void
17
+ def initialize: () -> void
18
+
19
+ # Non-blocking, lock-free check.
20
+ def running?: () -> untyped
21
+
22
+ # Transition to :draining.
23
+ def drain!: () -> untyped
24
+
25
+ # Transition to :stopped.
26
+ def stop!: () -> untyped
27
+
28
+ # Block until the state is no longer :running.
29
+ def wait_while_running: () -> untyped
30
+
31
+ # Block until the state is :stopped.
32
+ def wait_until_stopped: () -> untyped
33
+ end
34
+ end
@@ -0,0 +1,50 @@
1
+ # Generated from lib/zizq/middleware.rb with RBS::Inline
2
+
3
+ module Zizq
4
+ module Middleware
5
+ # A linked chain of middleware ending with a terminal.
6
+ #
7
+ # Each middleware must implement `#call(arg, chain)` where `chain` is
8
+ # the next link. The terminal implements `#call(arg)`.
9
+ #
10
+ # When no middleware is registered, `#call` delegates directly to the
11
+ # terminal with zero overhead.
12
+ #
13
+ # chain = Zizq::Middleware::Chain.new(dispatcher)
14
+ # chain.use(LoggingMiddleware.new)
15
+ # chain.use(MetricsMiddleware.new)
16
+ # chain.call(job)
17
+ # # MetricsMiddleware -> LoggingMiddleware -> dispatcher
18
+ #
19
+ # @rbs generic Arg -- the type flowing through the chain
20
+ # @rbs generic Ret -- the return type of the terminal
21
+ class Chain[Arg, Ret]
22
+ # The terminal callable at the end of the chain.
23
+ attr_reader terminal: untyped
24
+
25
+ def initialize: (untyped terminal) -> untyped
26
+
27
+ # Replace the terminal, invalidating any built chain.
28
+ def terminal=: (untyped terminal) -> untyped
29
+
30
+ # Append a middleware to the chain.
31
+ def use: (untyped middleware) -> untyped
32
+
33
+ # Execute the chain with the given argument.
34
+ def call: (untyped arg) -> untyped
35
+
36
+ private
37
+
38
+ def build: () -> untyped
39
+ end
40
+
41
+ # A single link in the middleware chain, connecting a middleware to
42
+ # the next link (or terminal).
43
+ class Link
44
+ def initialize: (untyped middleware, untyped next_link) -> untyped
45
+
46
+ # Invoke this middleware, passing the next link for continuation.
47
+ def call: (untyped arg) -> untyped
48
+ end
49
+ end
50
+ end