zizq 0.2.0 → 0.3.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.
@@ -0,0 +1,263 @@
1
+ # Copyright (c) 2026 Chris Corbyn <chris@zizq.io>
2
+ # Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ # rbs_inline: enabled
5
+ # frozen_string_literal: true
6
+
7
+ module Zizq
8
+ # Represents a Crontab schedule defined on the Zizq server.
9
+ #
10
+ # This requires a Pro license on the Zizq server.
11
+ #
12
+ # The actual data is lazily fetched when first accessed.
13
+ #
14
+ # Crontabs are used to define collections of recurring jobs that run on a
15
+ # specified schedule, such as at 2am on every Monday. Each entry on the
16
+ # Crontab is a single job enqueue, which the Zizq server automatically
17
+ # triggers at the correct point in time. Zizq uses standard Cron expression
18
+ # syntax (with support for seconds via 6-fields) to define entries.
19
+ #
20
+ # Entire schedules, and individual entries on a schedule, can be paused and
21
+ # resumed.
22
+ #
23
+ # By default schedules operate in the system time zone of the Zizq server
24
+ # but an explicit IANA timezone name can be specified when defining the
25
+ # Crontab.
26
+ class Crontab
27
+ # The name of the cron group that this schedule is backed by.
28
+ attr_reader :name #: String
29
+
30
+ # True if this schedule is paused.
31
+ #
32
+ # When paused, the scheduler continues to run but does not enqueue any jobs
33
+ # and only advances the timer.
34
+ attr_writer :paused #: bool?
35
+
36
+ # Initialize the Crontab with the given group name.
37
+ #
38
+ # @rbs name: String
39
+ def initialize(name)
40
+ @building = false #: bool
41
+ @materialized = false #: bool
42
+ @name = name #: String
43
+ @entries = {} #: Hash[String, Zizq::CrontabEntry]
44
+ @paused = false #: bool?
45
+ @paused_at = nil #: Float?
46
+ @resumed_at = nil #: Float?
47
+ end
48
+
49
+ # Fetch data from the Zizq server if not already fetched.
50
+ #
51
+ # Once fetched, this method becomes a no-op, unless #clear is called to
52
+ # remove the fetched data.
53
+ def materialize #: () -> self
54
+ unless @building || @materialized
55
+ materialize_with(Zizq.client.get_cron_group(name))
56
+ end
57
+
58
+ self
59
+ end
60
+
61
+ # Clear materialized data that was fetched from the Zizq server.
62
+ #
63
+ # This triggers a refetch when the data is next accessed.
64
+ def clear #: () -> self
65
+ @entries = {}
66
+ @paused = nil
67
+ @paused_at = nil
68
+ @resumed_at = nil
69
+ @materialized = false
70
+
71
+ self
72
+ end
73
+
74
+ # Delete this entire Crontab schedule and its entries.
75
+ def delete! #: () -> void
76
+ Zizq.client.delete_cron_group(name)
77
+ end
78
+
79
+ # Pause this entire Crontab schedule.
80
+ #
81
+ # All entries will stop enqueueing jobs, but the server continues to
82
+ # advance the schedule until it is resumed.
83
+ def pause! #: () -> void
84
+ materialize_with(Zizq.client.update_cron_group(name, paused: true))
85
+ end
86
+
87
+ # Resume this Crontab schedule if it is currently paused.
88
+ #
89
+ # Individual entries that are paused will remain paused.
90
+ def resume! #: () -> void
91
+ materialize_with(Zizq.client.update_cron_group(name, paused: false))
92
+ end
93
+
94
+ # Check if this schedule is currently paused.
95
+ def paused #: () -> bool?
96
+ materialize
97
+ @paused
98
+ end
99
+
100
+ # Check if this schedule is currently paused.
101
+ #
102
+ # Alias of #paused.
103
+ def paused? = paused #: () -> bool?
104
+
105
+ # Return the timestamp at which this Crontab schedule was last paused.
106
+ def paused_at #: () -> Float?
107
+ materialize
108
+ @paused_at
109
+ end
110
+
111
+ # Return the timestamp at which this Crontab schedule was last resumed.
112
+ def resumed_at #: () -> Float?
113
+ materialize
114
+ @resumed_at
115
+ end
116
+
117
+ # Return a Hash of Zizq::CrontabEntry instances keyed by their names.
118
+ #
119
+ # Each entry specifies the cron expression at which it executes,
120
+ # information about when it last/next enqueued a job, and details of the
121
+ # job that the entry enqueues.
122
+ def entries #: () -> Hash[String, Zizq::CrontabEntry]
123
+ materialize
124
+ @entries
125
+ end
126
+
127
+ # Redefine (replace) this Crontab schedule with another.
128
+ #
129
+ # This is equivalent to calling `Zizq.define_crontab` and is idempotent
130
+ # when given the same schedule more than once.
131
+ #
132
+ # @rbs ?timezone: String?
133
+ # @rbs ?paused: bool?
134
+ # @rbs &block: (Zizq::CrontabBuilder) -> void
135
+ # @rbs return: self
136
+ def redefine(timezone: nil, paused: nil, &block)
137
+ @building = true
138
+
139
+ yield CrontabBuilder.new(self, timezone:, paused:)
140
+
141
+ materialize_with(
142
+ Zizq.client.replace_cron_group(
143
+ name,
144
+ paused:,
145
+ entries: entries.values.map(&:to_params),
146
+ ),
147
+ )
148
+
149
+ @building = false
150
+
151
+ self
152
+ end
153
+
154
+ # Return a handle for the specified Zizq::CrontabEntry.
155
+ #
156
+ # The entry can be paused or resumed is isolation, can be deleted entirely
157
+ # or can be redefined (replaced) with another entry.
158
+ #
159
+ # @rbs name: String
160
+ # @rbs return: Zizq::CrontabEntry
161
+ def entry(name)
162
+ materialize
163
+ entries.fetch(name) do
164
+ entry = materialize_entry_with(
165
+ Zizq.client.get_cron_group_entry(self.name, name),
166
+ )
167
+ entries[name] = entry
168
+ end
169
+ end
170
+
171
+ # Define (or redefine) an entry with this Crontab schedule.
172
+ #
173
+ # Defining the same entry more than once is idempotent. If the entry does
174
+ # not exist, it is added to the schedule. If the entry already exists, it
175
+ # replaces the current entry.
176
+ #
177
+ # The return value is a Zizq::CrontabEntryBuilder instance, on which the
178
+ # caller must call one of the enqueue methods (`enqueue`, `enqueue_raw`,
179
+ # optionally chained onto `enqueue_with`, exactly the same as a regular job
180
+ # enqueue).
181
+ #
182
+ # All enqueue options are supported *except* `delay` and `ready_at` which
183
+ # make no sense for recurring jobs.
184
+ #
185
+ # Bulk enqueues are not supported.
186
+ #
187
+ # crontab.define_entry(
188
+ # "refresh_data_warehose",
189
+ # "*/15 * * * *",
190
+ # ).enqueue(RefreshDataWarehoseJob, incremental: true)
191
+ #
192
+ # @rbs name: String
193
+ # @rbs expression: String
194
+ # @rbs timezone: String?
195
+ # @rbs paused: bool?
196
+ # @rbs return: Zizq::CrontabEntryBuilder
197
+ def define_entry(name, expression, timezone: nil, paused: nil)
198
+ CrontabEntryBuilder.new(self, name, expression, timezone:, paused:) do |e|
199
+ entry = materialize_entry_with(
200
+ Zizq.client.replace_cron_group_entry(
201
+ self.name,
202
+ name,
203
+ expression: e.expression,
204
+ job: e.job.to_enqueue_params,
205
+ timezone: e.timezone,
206
+ paused: e.paused,
207
+ ),
208
+ )
209
+
210
+ materialize # in case this was the first entry operation
211
+
212
+ entry
213
+ end
214
+ end
215
+
216
+ private
217
+
218
+ # @rbs result: Zizq::Resources::CronGroup
219
+ # @rbs return: self
220
+ def materialize_with(result)
221
+ @paused = result.paused?
222
+ @paused_at = result.paused_at
223
+ @resumed_at = result.resumed_at
224
+
225
+ @entries = result.entries.map do |entry|
226
+ [
227
+ entry.name,
228
+ materialize_entry_with(entry),
229
+ ]
230
+ end.to_h
231
+
232
+ @materialized = true
233
+
234
+ self
235
+ end
236
+
237
+ # @rbs result: Zizq::Resources::CronEntry
238
+ # @rbs return: Zizq::CrontabEntry
239
+ def materialize_entry_with(result)
240
+ CrontabEntry.new(
241
+ self,
242
+ result.name,
243
+ result.expression,
244
+ job: EnqueueRequest.new(
245
+ type: result.job.type,
246
+ queue: result.job.queue,
247
+ priority: result.job.priority,
248
+ payload: result.job.payload,
249
+ retry_limit: result.job.retry_limit,
250
+ backoff: result.job.backoff,
251
+ retention: result.job.retention,
252
+ unique_key: result.job.unique_key,
253
+ unique_while: result.job.unique_while,
254
+ ),
255
+ paused: result.paused?,
256
+ paused_at: result.paused_at,
257
+ resumed_at: result.resumed_at,
258
+ last_enqueue_at: result.last_enqueue_at,
259
+ next_enqueue_at: result.next_enqueue_at,
260
+ )
261
+ end
262
+ end
263
+ end
@@ -0,0 +1,52 @@
1
+ # Copyright (c) 2026 Chris Corbyn <chris@zizq.io>
2
+ # Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ # rbs_inline: enabled
5
+ # frozen_string_literal: true
6
+
7
+ module Zizq
8
+ # Builder used to configure a Zizq::Crontab instance.
9
+ #
10
+ # Instances of this class are returned from `Zizq.define_crontab`. See
11
+ # documentation for that method for usage.
12
+ class CrontabBuilder
13
+ # The Crontab instance that this builder configures.
14
+ attr_reader :target #: Zizq::Crontab
15
+
16
+ # Optional timezone to be applied to all entries by default.
17
+ attr_accessor :timezone #: String?
18
+
19
+ # Initialize the builder with the given Crontab instance.
20
+ #
21
+ # @rbs target: Zizq::Crontab
22
+ # @rbs timezone: String?
23
+ # @rbs paused: bool?
24
+ def initialize(target, timezone: nil, paused: nil)
25
+ @target = target.clear
26
+ @timezone = timezone
27
+
28
+ target.paused = paused
29
+ end
30
+
31
+ # Add or replace an entry on the schedule
32
+ #
33
+ # If no entry with the given name exists, it is added to schedule. If an
34
+ # entry with the same name exist, this entry replaces that entry. If the
35
+ # entry is the same as the original, the result is idempotent.
36
+ #
37
+ # @rbs name: String
38
+ # @rbs expression: String
39
+ # @rbs timezone: String?
40
+ # @rbs paused: bool?
41
+ # @rbs return: Zizq::CrontabEntryBuilder
42
+ def define_entry(name, expression, timezone: self.timezone, paused: nil)
43
+ CrontabEntryBuilder.new(
44
+ target,
45
+ name,
46
+ expression,
47
+ timezone:,
48
+ paused:,
49
+ )
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,182 @@
1
+ # Copyright (c) 2026 Chris Corbyn <chris@zizq.io>
2
+ # Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ # rbs_inline: enabled
5
+ # frozen_string_literal: true
6
+
7
+ module Zizq
8
+ # Represents a single entry within a Crontab schedule.
9
+ #
10
+ # Each entry specifies the cron expression at which it executes,
11
+ # information about when it last/next enqueued a job, and details of the
12
+ # job that the entry enqueues.
13
+ #
14
+ # Entries can be paused or resumed, and can be deleted or redefined in place.
15
+ class CrontabEntry
16
+ # The Crontab schedule to which this entry belongs.
17
+ attr_reader :crontab #: Zizq::Crontab
18
+
19
+ # The name of this entry within the schedule.
20
+ attr_reader :name #: String
21
+
22
+ # The cron expression used to define the schedule for the entry.
23
+ #
24
+ # Both standard 5-field and enhanced 6-field cron (with seconds) are
25
+ # supported, along with @daily, @weekly etc.
26
+ attr_reader :expression #: String
27
+
28
+ # The timezone in which the schedule entry is processed.
29
+ #
30
+ # Defaults to the Zizq server timezone unless specified.
31
+ attr_reader :timezone #: String?
32
+
33
+ # Parameters that will be used to enqueue jobs each time the schedule fires.
34
+ #
35
+ # These are the same parameters as those used to enqueue jobs normally.
36
+ attr_reader :job #: EnqueueRequest
37
+
38
+ # True if this entry is currrently paused.
39
+ attr_reader :paused #: bool?
40
+
41
+ # The timestamp at which this entry was last paused.
42
+ attr_reader :paused_at #: Float?
43
+
44
+ # The timestamp at which this entry was last resumed.
45
+ attr_reader :resumed_at #: Float?
46
+
47
+ # The timestamp at which a job was last enqueued for this entry.
48
+ attr_reader :last_enqueue_at #: Float?
49
+ #
50
+ # The timestamp at which the next job will be enqueued for this entry.
51
+ attr_reader :next_enqueue_at #: Float?
52
+
53
+ # Initialize the entry with all configured parameters.
54
+ #
55
+ # @rbs crontab: Zizq::Crontab
56
+ # @rbs name: String
57
+ # @rbs expression: String
58
+ # @rbs timezone: String?
59
+ # @rbs job: EnqueueRequest
60
+ # @rbs paused: bool?
61
+ # @rbs paused_at: Float?
62
+ # @rbs resumed_at: Float?
63
+ # @rbs last_enqueue_at: Float?
64
+ # @rbs next_enqueue_at: Float?
65
+ def initialize(crontab,
66
+ name,
67
+ expression,
68
+ job:,
69
+ timezone: nil,
70
+ paused: nil,
71
+ paused_at: nil,
72
+ resumed_at: nil,
73
+ last_enqueue_at: nil,
74
+ next_enqueue_at: nil)
75
+ @crontab = crontab
76
+ @name = name
77
+ @expression = expression
78
+ @timezone = timezone
79
+ @job = job
80
+ @paused = paused
81
+ @paused_at = paused_at
82
+ @resumed_at = resumed_at
83
+ @last_enqueue_at = last_enqueue_at
84
+ @next_enqueue_at = next_enqueue_at
85
+ end
86
+
87
+ # Replace this entry with another.
88
+ #
89
+ # This is equivalent to calling `crontab.define_entry` with the same name.
90
+ #
91
+ # @rbs expression: String
92
+ # @rbs timezone: String?
93
+ # @rbs paused: bool?
94
+ # @rbs return: Zizq::CrontabEntryBuilder
95
+ def redefine(expression, timezone: nil, paused: nil)
96
+ CrontabEntryBuilder.new(crontab, name, expression, timezone:, paused:) do |e|
97
+ materialize_with(
98
+ Zizq.client.replace_cron_group_entry(
99
+ crontab.name,
100
+ name,
101
+ expression: e.expression,
102
+ job: e.job.to_enqueue_params,
103
+ timezone: e.timezone,
104
+ paused: e.paused,
105
+ ),
106
+ )
107
+ end
108
+ end
109
+
110
+ # Delete the entry from the schedule.
111
+ def delete! #: () -> void
112
+ Zizq.client.delete_cron_group_entry(crontab.name, name)
113
+ crontab.entries.delete(name)
114
+ end
115
+
116
+ # Pause the entry within the schedule.
117
+ #
118
+ # This is independent of the paused state of the Crontab itself.
119
+ def pause! #: () -> void
120
+ materialize_with(
121
+ Zizq.client.update_cron_group_entry(
122
+ crontab.name,
123
+ name,
124
+ paused: true,
125
+ ),
126
+ )
127
+ end
128
+
129
+ # Resume this entry if it is currently paused.
130
+ #
131
+ # If the parent Crontab itself is paused, the entry will still not enqueue
132
+ # jobs until the Crontab is resumed.
133
+ def resume! #: () -> void
134
+ materialize_with(
135
+ Zizq.client.update_cron_group_entry(
136
+ crontab.name,
137
+ name,
138
+ paused: false,
139
+ ),
140
+ )
141
+ end
142
+
143
+ # @private
144
+ # @rbs return: Zizq::cron_entry_params
145
+ def to_params
146
+ {
147
+ name:,
148
+ expression:,
149
+ timezone:,
150
+ job: job.to_enqueue_params,
151
+ paused:,
152
+ }.compact #: Zizq::cron_entry_params
153
+ end
154
+
155
+ private
156
+
157
+ # @rbs result: Zizq::Resources::CronEntry
158
+ # @rbs return: self
159
+ def materialize_with(result)
160
+ @expression = result.expression
161
+ @timezone = result.timezone
162
+ @paused = result.paused?
163
+ @paused_at = result.paused_at
164
+ @resumed_at = result.resumed_at
165
+ @last_enqueue_at = result.last_enqueue_at
166
+ @next_enqueue_at = result.next_enqueue_at
167
+ @job = EnqueueRequest.new(
168
+ type: result.job.type,
169
+ queue: result.job.queue,
170
+ priority: result.job.priority,
171
+ payload: result.job.payload,
172
+ retry_limit: result.job.retry_limit,
173
+ backoff: result.job.backoff,
174
+ retention: result.job.retention,
175
+ unique_key: result.job.unique_key,
176
+ unique_while: result.job.unique_while,
177
+ )
178
+
179
+ self
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,133 @@
1
+ # Copyright (c) 2026 Chris Corbyn <chris@zizq.io>
2
+ # Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ # rbs_inline: enabled
5
+ # frozen_string_literal: true
6
+
7
+ module Zizq
8
+ # Builder class used to define individual entries within a Crontab schedule.
9
+ #
10
+ # This is used internally by `Zizq.define_crontab`. See documentation for
11
+ # that method for full details.
12
+ #
13
+ # Callers *must* call one of the enqueue methods to complete the build
14
+ # process.
15
+ class CrontabEntryBuilder
16
+ # The Crontab instance onto which entries are applied.
17
+ attr_reader :target #: Zizq::Crontab
18
+
19
+ # The name of the entry being built.
20
+ attr_reader :name #: String
21
+
22
+ # The cron expression for the entry.
23
+ attr_reader :expression #: String
24
+
25
+ # Optional timezone for the entry.
26
+ #
27
+ # Defaults to the Zizq server timezone when not specified.
28
+ attr_reader :timezone #: String?
29
+
30
+ # True if this entry will be paused.
31
+ attr_reader :paused #: bool?
32
+
33
+ # Callback through which the built entry is passed before being added to
34
+ # the Crontab schedule.
35
+ #
36
+ # The callback receives the Zizq::CrontabEntry instance and may return an
37
+ # alternative instance to be used after it has done any processing on the
38
+ # entry.
39
+ attr_reader :callback #: ^(Zizq::CrontabEntry) -> Zizq::CrontabEntry
40
+
41
+ # Initialize the builder with the given inputs.
42
+ #
43
+ # @rbs target: Zizq::Crontab
44
+ # @rbs name: String
45
+ # @rbs expression: String
46
+ # @rbs timezone: String?
47
+ # @rbs paused: bool?
48
+ # @rbs ?&block: (Zizq::CrontabEntry) -> Zizq::CrontabEntry
49
+ def initialize(target,
50
+ name,
51
+ expression,
52
+ timezone: nil,
53
+ paused: nil,
54
+ &block)
55
+ @target = target
56
+ @name = name
57
+ @expression = expression
58
+ @timezone = timezone
59
+ @paused = paused
60
+ @callback = block || :itself.to_proc
61
+ end
62
+
63
+ # Enqueue a Zizq::Job or ActiveJob class using Zizq::ActiveJobConfig via
64
+ # this entry.
65
+ #
66
+ # @rbs job_class: Class & Zizq::JobConfig
67
+ # @rbs args: Array[untyped]
68
+ # @rbs kwargs: Hash[Symbol, untyped]
69
+ # @rbs &block: ?(EnqueueRequest) -> void
70
+ # @rbs return: void
71
+ def enqueue(job_class, *args, **kwargs, &block)
72
+ push_entry(Zizq.build_enqueue_request(job_class, *args, **kwargs, &block))
73
+ end
74
+
75
+ # Process a raw job enqueue for this entry.
76
+ #
77
+ # This is used for low-level or cross-language support.
78
+ #
79
+ # @rbs queue: String
80
+ # @rbs type: String
81
+ # @rbs payload: untyped
82
+ # @rbs priority: Integer?
83
+ # @rbs ready_at: Zizq::to_f?
84
+ # @rbs retry_limit: Integer?
85
+ # @rbs backoff: Zizq::backoff?
86
+ # @rbs retention: Zizq::retention?
87
+ # @rbs unique_key: String?
88
+ # @rbs unique_while: Zizq::unique_scope?
89
+ # @rbs return: void
90
+ def enqueue_raw(queue:, type:, payload:, **opts)
91
+ push_entry(EnqueueRequest.new(queue:, type:, payload:, **opts))
92
+ end
93
+
94
+ # Bulk enqueues are not supported via cron.
95
+ #
96
+ # @rbs &block: (BulkEnqueue) -> void
97
+ # @rbs return: self
98
+ def enqueue_bulk(&block)
99
+ raise NotImplementedError, 'bulk enqueues are not supported via cron'
100
+ end
101
+
102
+ # Provide common fields to be used when enqueueing a job.
103
+ #
104
+ # @rbs overrides: Hash[Symbol, untyped]
105
+ # @rbs return: EnqueueWith
106
+ def enqueue_with(**overrides)
107
+ EnqueueWith.new(self, overrides)
108
+ end
109
+
110
+ private
111
+
112
+ # @rbs job: EnqueueRequest
113
+ # @rbs return: untyped
114
+ def push_entry(req)
115
+ if req.ready_at || req.delay
116
+ raise ArgumentError, 'delayed job are not permitted via cron'
117
+ end
118
+
119
+ entry = callback.call(
120
+ CrontabEntry.new(
121
+ target,
122
+ name,
123
+ expression,
124
+ job: req,
125
+ timezone:,
126
+ paused:,
127
+ ),
128
+ )
129
+
130
+ target.entries[entry.name] = entry
131
+ end
132
+ end
133
+ end
@@ -68,7 +68,7 @@ module Zizq
68
68
  # Enqueue a job class via the underlying target, applying the scoped
69
69
  # overrides before invoking any caller-supplied block.
70
70
  #
71
- # @rbs job_class: Class & Zizq::job_class
71
+ # @rbs job_class: Class & Zizq::JobConfig
72
72
  # @rbs args: Array[untyped]
73
73
  # @rbs kwargs: Hash[Symbol, untyped]
74
74
  # @rbs &block: ?(EnqueueRequest) -> void
data/lib/zizq/job.rb CHANGED
@@ -46,11 +46,15 @@ module Zizq
46
46
  def self.call(job)
47
47
  job_class = Object.const_get(job.type)
48
48
 
49
- unless job_class.is_a?(Class) && job_class.include?(Zizq::Job)
49
+ unless (
50
+ job_class.is_a?(Class) &&
51
+ job_class.include?(Zizq::Job) &&
52
+ job_class.is_a?(Zizq::JobConfig)
53
+ )
50
54
  raise "#{job.type} does not include Zizq::Job"
51
55
  end
52
56
 
53
- zizq_job_class = job_class #: Zizq::job_class
57
+ zizq_job_class = job_class #: (Class & Zizq::JobConfig & Zizq::job_class)
54
58
  instance = zizq_job_class.new
55
59
  instance.set_zizq_job(job)
56
60
 
data/lib/zizq/query.rb CHANGED
@@ -161,7 +161,7 @@ module Zizq
161
161
  # Sets the type filter to the class name and adds a jq payload filter
162
162
  # for an exact match of the serialized arguments.
163
163
  #
164
- # @rbs job_class: Zizq::job_class
164
+ # @rbs job_class: Class && Zizq::JobConfig
165
165
  # @rbs *args: untyped
166
166
  # @rbs **kwargs: untyped
167
167
  # @rbs return: Query
@@ -179,7 +179,7 @@ module Zizq
179
179
  # The job class must include `Zizq::Job` or for Active Job classes must
180
180
  # extend `Zizq::ActiveJobConfig`.
181
181
  #
182
- # @rbs job_class: Zizq::job_class
182
+ # @rbs job_class: Class & Zizq::JobConfig
183
183
  # @rbs *args: untyped
184
184
  # @rbs **kwargs: untyped
185
185
  # @rbs return: Query
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2026 Chris Corbyn <chris@zizq.io>
2
+ # Licensed under the MIT License. See LICENSE file for details.
3
+
4
+ # rbs_inline: enabled
5
+ # frozen_string_literal: true
6
+
7
+ module Zizq
8
+ module Resources
9
+ # Typed wrapper around a cron entry response hash.
10
+ class CronEntry < Resource
11
+ def name = @data["name"] #: () -> String
12
+ def expression = @data["expression"] #: () -> String
13
+ def timezone = @data["timezone"] #: () -> String?
14
+ def paused = @data["paused"] #: () -> bool
15
+ def paused? = paused #: () -> bool
16
+ def paused_at = ms_to_seconds(@data["paused_at"]) #: () -> Float?
17
+ def resumed_at = ms_to_seconds(@data["resumed_at"]) #: () -> Float?
18
+ def next_enqueue_at = ms_to_seconds(@data["next_enqueue_at"]) #: () -> Float?
19
+ def last_enqueue_at = ms_to_seconds(@data["last_enqueue_at"]) #: () -> Float?
20
+
21
+ # Returns the job template for this entry.
22
+ def job #: () -> JobTemplate
23
+ JobTemplate.new(client, @data["job"])
24
+ end
25
+ end
26
+ end
27
+ end