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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +94 -0
- data/bin/profile-worker +145 -0
- data/bin/zizq-worker +174 -0
- data/lib/active_job/queue_adapters/zizq_adapter.rb +109 -0
- data/lib/zizq/ack_processor.rb +132 -0
- data/lib/zizq/active_job_config.rb +122 -0
- data/lib/zizq/backoff.rb +50 -0
- data/lib/zizq/bulk_enqueue.rb +87 -0
- data/lib/zizq/client.rb +982 -0
- data/lib/zizq/configuration.rb +164 -0
- data/lib/zizq/enqueue_request.rb +178 -0
- data/lib/zizq/enqueue_with.rb +109 -0
- data/lib/zizq/error.rb +43 -0
- data/lib/zizq/job.rb +188 -0
- data/lib/zizq/job_config.rb +244 -0
- data/lib/zizq/lifecycle.rb +58 -0
- data/lib/zizq/middleware.rb +79 -0
- data/lib/zizq/query.rb +566 -0
- data/lib/zizq/resources/error_enumerator.rb +241 -0
- data/lib/zizq/resources/error_page.rb +19 -0
- data/lib/zizq/resources/error_record.rb +19 -0
- data/lib/zizq/resources/job.rb +124 -0
- data/lib/zizq/resources/job_page.rb +57 -0
- data/lib/zizq/resources/page.rb +77 -0
- data/lib/zizq/resources/resource.rb +45 -0
- data/lib/zizq/resources.rb +16 -0
- data/lib/zizq/version.rb +9 -0
- data/lib/zizq/worker.rb +467 -0
- data/lib/zizq.rb +269 -0
- data/sig/generated/zizq/ack_processor.rbs +73 -0
- data/sig/generated/zizq/active_job_config.rbs +74 -0
- data/sig/generated/zizq/backoff.rbs +34 -0
- data/sig/generated/zizq/bulk_enqueue.rbs +72 -0
- data/sig/generated/zizq/client.rbs +419 -0
- data/sig/generated/zizq/configuration.rbs +95 -0
- data/sig/generated/zizq/enqueue_request.rbs +94 -0
- data/sig/generated/zizq/enqueue_with.rbs +88 -0
- data/sig/generated/zizq/error.rbs +41 -0
- data/sig/generated/zizq/job.rbs +136 -0
- data/sig/generated/zizq/job_config.rbs +150 -0
- data/sig/generated/zizq/lifecycle.rbs +34 -0
- data/sig/generated/zizq/middleware.rbs +50 -0
- data/sig/generated/zizq/query.rbs +327 -0
- data/sig/generated/zizq/resources/error_enumerator.rbs +148 -0
- data/sig/generated/zizq/resources/error_page.rbs +13 -0
- data/sig/generated/zizq/resources/error_record.rbs +20 -0
- data/sig/generated/zizq/resources/job.rbs +89 -0
- data/sig/generated/zizq/resources/job_page.rbs +33 -0
- data/sig/generated/zizq/resources/page.rbs +47 -0
- data/sig/generated/zizq/resources/resource.rbs +26 -0
- data/sig/generated/zizq/version.rbs +5 -0
- data/sig/generated/zizq/worker.rbs +152 -0
- data/sig/generated/zizq.rbs +180 -0
- data/sig/zizq.rbs +111 -0
- 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
|