sidekiq 8.0.0.beta1 → 8.0.0.beta2
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/Changes.md +15 -4
- data/lib/sidekiq/api.rb +12 -0
- data/lib/sidekiq/capsule.rb +5 -5
- data/lib/sidekiq/component.rb +10 -0
- data/lib/sidekiq/iterable_job.rb +1 -0
- data/lib/sidekiq/job/iterable.rb +11 -0
- data/lib/sidekiq/job_retry.rb +15 -3
- data/lib/sidekiq/metrics/query.rb +70 -42
- data/lib/sidekiq/metrics/shared.rb +4 -1
- data/lib/sidekiq/metrics/tracking.rb +9 -7
- data/lib/sidekiq/version.rb +1 -1
- data/lib/sidekiq/web/action.rb +4 -0
- data/lib/sidekiq/web/application.rb +28 -19
- data/lib/sidekiq/web/helpers.rb +1 -1
- data/lib/sidekiq.rb +1 -1
- data/web/assets/javascripts/base-charts.js +4 -2
- data/web/assets/javascripts/chartjs-adapter-date-fns.min.js +7 -0
- data/web/assets/javascripts/metrics.js +15 -33
- data/web/assets/stylesheets/style.css +1 -1
- data/web/views/_job_info.erb +2 -2
- data/web/views/_metrics_period_select.erb +12 -9
- data/web/views/_nav.erb +1 -1
- data/web/views/dashboard.erb +1 -0
- data/web/views/layout.erb +1 -1
- data/web/views/metrics.erb +13 -22
- data/web/views/metrics_for_job.erb +7 -5
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1701d726f9433f505053b19c5c708c76ec16cc815cef96492f085e914f52c016
|
4
|
+
data.tar.gz: 81504bd7aad6e5815027008a4d61908d898742b4f64ceb518e1fff078de228a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96c78d5229328a1fcfc4663afc4c32437ec8438e246641739409876f608aa90ad19aca7185f0ae7b1e2a26291e105bf3fccda538dde508d1aaea854c4fcc9ef6
|
7
|
+
data.tar.gz: cbb162697c348a02d4b9cd35a8f215d6b42e381ba1236ad4c5b41ccbcd55f4a8a601087c7bb4cbf3f9c63447c2406544b248465735398d66e55e981577dcbbc9
|
data/Changes.md
CHANGED
@@ -6,26 +6,37 @@ HEAD / main
|
|
6
6
|
----------
|
7
7
|
|
8
8
|
- **WARNING** The underlying class name for Active Jobs has changed from `ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper` to `Sidekiq::ActiveJob::Wrapper`.
|
9
|
-
|
10
|
-
|
11
|
-
issues with JSON and JavaScript's 53-bit Floats.
|
12
|
-
`"created_at" => 1234567890.123456` -> `"created_at" => 1234567890123`.
|
9
|
+
The old name will still work in 8.x.
|
10
|
+
- **WARNING** The `created_at`, `enqueued_at`, `failed_at` and `retried_at` attributes are now stored as epoch milliseconds, rather than epoch floats.
|
11
|
+
This is meant to avoid precision issues with JSON and JavaScript's 53-bit Floats.
|
12
|
+
Example: `"created_at" => 1234567890.123456` -> `"created_at" => 1234567890123`.
|
13
13
|
- **NEW FEATURE** Job Profiling is now supported with [Vernier](https://vernier.prof)
|
14
14
|
which makes it really easy to performance tune your slow jobs.
|
15
15
|
The Web UI contains a new **Profiles** tab to view any collected profile data.
|
16
16
|
Please read the new [Profiling](https://github.com/sidekiq/sidekiq/wiki/Profiling) wiki page for details.
|
17
|
+
- **NEW FEATURE** Job Metrics now store up to 72 hours of data and the Web UI allows display of 24/48/72 hours. [#6614]
|
17
18
|
- CurrentAttribute support now uses `ActiveJob::Arguments` to serialize the context object, supporting Symbols and GlobalID.
|
18
19
|
The change should be backwards compatible. [#6510]
|
19
20
|
- Freshen up `Sidekiq::Web` to simplify the code and improve security [#6532]
|
20
21
|
The CSS has been rewritten from scratch to remove the Bootstrap framework.
|
22
|
+
- Add `on_cancel` callback for iterable jobs [#6607]
|
23
|
+
- Add `cursor` reader to get the current cursor inside iterable jobs [#6606]
|
21
24
|
- Default error logging has been modified to use Ruby's `Exception#detailed_message` and `#full_message` APIs.
|
22
25
|
- CI now runs against Redis, Dragonfly and Valkey.
|
26
|
+
- Job tags now allow custom CSS display [#6595]
|
23
27
|
- The Web UI's language picker now shows options in the native language
|
24
28
|
- Remove global variable usage within the codebase
|
25
29
|
- Adjust Sidekiq's default thread priority to -1 for a 50ms timeslice.
|
26
30
|
This can help avoid TimeoutErrors when Sidekiq is overloaded. [#6543]
|
27
31
|
- Support: Redis 7.2+, Ruby 3.2+, Rails 7.0+
|
28
32
|
|
33
|
+
7.3.9
|
34
|
+
----------
|
35
|
+
|
36
|
+
- Only require activejob if necessary [#6584]
|
37
|
+
- Fix iterable job cancellation [#6589]
|
38
|
+
- Web UI accessibility improvements [#6604]
|
39
|
+
|
29
40
|
7.3.8
|
30
41
|
----------
|
31
42
|
|
data/lib/sidekiq/api.rb
CHANGED
@@ -441,6 +441,18 @@ module Sidekiq
|
|
441
441
|
self["bid"]
|
442
442
|
end
|
443
443
|
|
444
|
+
def failed_at
|
445
|
+
if self["failed_at"]
|
446
|
+
time_from_timestamp(self["failed_at"])
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
def retried_at
|
451
|
+
if self["retried_at"]
|
452
|
+
time_from_timestamp(self["retried_at"])
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
444
456
|
def enqueued_at
|
445
457
|
if self["enqueued_at"]
|
446
458
|
time_from_timestamp(self["enqueued_at"])
|
data/lib/sidekiq/capsule.rb
CHANGED
@@ -11,12 +11,12 @@ module Sidekiq
|
|
11
11
|
# This capsule will pull jobs from the "single" queue and process
|
12
12
|
# the jobs with one thread, meaning the jobs will be processed serially.
|
13
13
|
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
14
|
+
# Sidekiq.configure_server do |config|
|
15
|
+
# config.capsule("single-threaded") do |cap|
|
16
|
+
# cap.concurrency = 1
|
17
|
+
# cap.queues = %w(single)
|
18
|
+
# end
|
18
19
|
# end
|
19
|
-
# end
|
20
20
|
class Capsule
|
21
21
|
include Sidekiq::Component
|
22
22
|
extend Forwardable
|
data/lib/sidekiq/component.rb
CHANGED
@@ -23,6 +23,16 @@ module Sidekiq
|
|
23
23
|
module Component # :nodoc:
|
24
24
|
attr_reader :config
|
25
25
|
|
26
|
+
# This is epoch milliseconds, appropriate for persistence
|
27
|
+
def real_ms
|
28
|
+
::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond)
|
29
|
+
end
|
30
|
+
|
31
|
+
# used for time difference and relative comparisons, not persistence.
|
32
|
+
def mono_ms
|
33
|
+
::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :millisecond)
|
34
|
+
end
|
35
|
+
|
26
36
|
def watchdog(last_words)
|
27
37
|
yield
|
28
38
|
rescue Exception => ex
|
data/lib/sidekiq/iterable_job.rb
CHANGED
data/lib/sidekiq/job/iterable.rb
CHANGED
@@ -64,6 +64,10 @@ module Sidekiq
|
|
64
64
|
@_cancelled
|
65
65
|
end
|
66
66
|
|
67
|
+
def cursor
|
68
|
+
@_cursor.freeze
|
69
|
+
end
|
70
|
+
|
67
71
|
# A hook to override that will be called when the job starts iterating.
|
68
72
|
#
|
69
73
|
# It is called only once, for the first time.
|
@@ -91,6 +95,11 @@ module Sidekiq
|
|
91
95
|
def on_stop
|
92
96
|
end
|
93
97
|
|
98
|
+
# A hook to override that will be called when the job is cancelled.
|
99
|
+
#
|
100
|
+
def on_cancel
|
101
|
+
end
|
102
|
+
|
94
103
|
# A hook to override that will be called when the job finished iterating.
|
95
104
|
#
|
96
105
|
def on_complete
|
@@ -182,6 +191,7 @@ module Sidekiq
|
|
182
191
|
|
183
192
|
def iterate_with_enumerator(enumerator, arguments)
|
184
193
|
if is_cancelled?
|
194
|
+
on_cancel
|
185
195
|
logger.info { "Job cancelled" }
|
186
196
|
return true
|
187
197
|
end
|
@@ -200,6 +210,7 @@ module Sidekiq
|
|
200
210
|
state_flushed_at = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
201
211
|
if cancelled
|
202
212
|
@_cancelled = true
|
213
|
+
on_cancel
|
203
214
|
logger.info { "Job cancelled" }
|
204
215
|
return true
|
205
216
|
end
|
data/lib/sidekiq/job_retry.rb
CHANGED
@@ -139,6 +139,10 @@ module Sidekiq
|
|
139
139
|
|
140
140
|
private
|
141
141
|
|
142
|
+
def now_ms
|
143
|
+
::Process.clock_gettime(::Process::CLOCK_REALTIME, :millisecond)
|
144
|
+
end
|
145
|
+
|
142
146
|
# Note that +jobinst+ can be nil here if an error is raised before we can
|
143
147
|
# instantiate the job instance. All access must be guarded and
|
144
148
|
# best effort.
|
@@ -156,10 +160,10 @@ module Sidekiq
|
|
156
160
|
msg["error_message"] = m
|
157
161
|
msg["error_class"] = exception.class.name
|
158
162
|
count = if msg["retry_count"]
|
159
|
-
msg["retried_at"] =
|
163
|
+
msg["retried_at"] = now_ms
|
160
164
|
msg["retry_count"] += 1
|
161
165
|
else
|
162
|
-
msg["failed_at"] =
|
166
|
+
msg["failed_at"] = now_ms
|
163
167
|
msg["retry_count"] = 0
|
164
168
|
end
|
165
169
|
|
@@ -177,7 +181,7 @@ module Sidekiq
|
|
177
181
|
return retries_exhausted(jobinst, msg, exception) if count >= max_retry_attempts
|
178
182
|
|
179
183
|
rf = msg["retry_for"]
|
180
|
-
return retries_exhausted(jobinst, msg, exception) if rf && ((msg["failed_at"] + rf) < Time.now
|
184
|
+
return retries_exhausted(jobinst, msg, exception) if rf && (time_for(msg["failed_at"]) + rf) < Time.now
|
181
185
|
|
182
186
|
strategy, delay = delay_for(jobinst, count, exception, msg)
|
183
187
|
case strategy
|
@@ -197,6 +201,14 @@ module Sidekiq
|
|
197
201
|
end
|
198
202
|
end
|
199
203
|
|
204
|
+
def time_for(item)
|
205
|
+
if item.is_a?(Float)
|
206
|
+
Time.at(item)
|
207
|
+
else
|
208
|
+
Time.at(item / 1000, item % 1000)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
200
212
|
# returns (strategy, seconds)
|
201
213
|
def delay_for(jobinst, count, exception, msg)
|
202
214
|
rv = begin
|
@@ -10,7 +10,7 @@ module Sidekiq
|
|
10
10
|
# Caller sets a set of attributes to act as filters. {#fetch} will call
|
11
11
|
# Redis and return a Hash of results.
|
12
12
|
#
|
13
|
-
# NB: all metrics and times/dates are UTC only. We
|
13
|
+
# NB: all metrics and times/dates are UTC only. We explicitly do not
|
14
14
|
# support timezones.
|
15
15
|
class Query
|
16
16
|
def initialize(pool: nil, now: Time.now)
|
@@ -19,23 +19,46 @@ module Sidekiq
|
|
19
19
|
@klass = nil
|
20
20
|
end
|
21
21
|
|
22
|
+
ROLLUPS = {
|
23
|
+
# minutely aggregates per minute
|
24
|
+
minutely: [60, ->(time) { time.strftime("j|%y%m%d|%-H:%M") }],
|
25
|
+
# hourly aggregates every 10 minutes so we'll have six data points per hour
|
26
|
+
hourly: [600, ->(time) {
|
27
|
+
m = time.min
|
28
|
+
mins = (m < 10) ? "0" : m.to_s[0]
|
29
|
+
time.strftime("j|%y%m%d|%-H:#{mins}")
|
30
|
+
}]
|
31
|
+
}
|
32
|
+
|
22
33
|
# Get metric data for all jobs from the last hour
|
23
34
|
# +class_filter+: return only results for classes matching filter
|
24
|
-
|
25
|
-
|
26
|
-
|
35
|
+
# +minutes+: the number of fine-grained minute buckets to retrieve
|
36
|
+
# +hours+: the number of coarser-grained 10-minute buckets to retrieve, in hours
|
37
|
+
def top_jobs(class_filter: nil, minutes: nil, hours: nil)
|
27
38
|
time = @time
|
39
|
+
minutes = 60 unless minutes || hours
|
40
|
+
|
41
|
+
# DoS protection, sanity check
|
42
|
+
minutes = 60 if minutes && minutes > 480
|
43
|
+
hours = 72 if hours && hours > 72
|
44
|
+
|
45
|
+
granularity = hours ? :hourly : :minutely
|
46
|
+
result = Result.new(granularity)
|
47
|
+
result.ends_at = time
|
48
|
+
count = hours ? hours * 6 : minutes
|
49
|
+
stride, keyproc = ROLLUPS[granularity]
|
50
|
+
|
28
51
|
redis_results = @pool.with do |conn|
|
29
52
|
conn.pipelined do |pipe|
|
30
|
-
|
31
|
-
key =
|
53
|
+
count.times do |idx|
|
54
|
+
key = keyproc.call(time)
|
32
55
|
pipe.hgetall key
|
33
|
-
|
34
|
-
time -= 60
|
56
|
+
time -= stride
|
35
57
|
end
|
36
58
|
end
|
37
59
|
end
|
38
60
|
|
61
|
+
result.starts_at = time
|
39
62
|
time = @time
|
40
63
|
redis_results.each do |hash|
|
41
64
|
hash.each do |k, v|
|
@@ -43,63 +66,66 @@ module Sidekiq
|
|
43
66
|
next if class_filter && !class_filter.match?(kls)
|
44
67
|
result.job_results[kls].add_metric metric, time, v.to_i
|
45
68
|
end
|
46
|
-
time -=
|
69
|
+
time -= stride
|
47
70
|
end
|
48
71
|
|
49
|
-
result.marks = fetch_marks(result.starts_at..result.ends_at)
|
50
|
-
|
72
|
+
result.marks = fetch_marks(result.starts_at..result.ends_at, granularity)
|
51
73
|
result
|
52
74
|
end
|
53
75
|
|
54
|
-
def for_job(klass, minutes:
|
55
|
-
result = Result.new
|
56
|
-
|
76
|
+
def for_job(klass, minutes: nil, hours: nil)
|
57
77
|
time = @time
|
78
|
+
minutes = 60 unless minutes || hours
|
79
|
+
|
80
|
+
# DoS protection, sanity check
|
81
|
+
minutes = 60 if minutes && minutes > 480
|
82
|
+
hours = 72 if hours && hours > 72
|
83
|
+
|
84
|
+
granularity = hours ? :hourly : :minutely
|
85
|
+
result = Result.new(granularity)
|
86
|
+
result.ends_at = time
|
87
|
+
count = hours ? hours * 6 : minutes
|
88
|
+
stride, keyproc = ROLLUPS[granularity]
|
89
|
+
|
58
90
|
redis_results = @pool.with do |conn|
|
59
91
|
conn.pipelined do |pipe|
|
60
|
-
|
61
|
-
key =
|
92
|
+
count.times do |idx|
|
93
|
+
key = keyproc.call(time)
|
62
94
|
pipe.hmget key, "#{klass}|ms", "#{klass}|p", "#{klass}|f"
|
63
|
-
|
64
|
-
time -= 60
|
95
|
+
time -= stride
|
65
96
|
end
|
66
97
|
end
|
67
98
|
end
|
68
99
|
|
100
|
+
result.starts_at = time
|
69
101
|
time = @time
|
70
102
|
@pool.with do |conn|
|
71
103
|
redis_results.each do |(ms, p, f)|
|
72
104
|
result.job_results[klass].add_metric "ms", time, ms.to_i if ms
|
73
105
|
result.job_results[klass].add_metric "p", time, p.to_i if p
|
74
106
|
result.job_results[klass].add_metric "f", time, f.to_i if f
|
75
|
-
result.job_results[klass].add_hist time, Histogram.new(klass).fetch(conn, time).reverse
|
76
|
-
time -=
|
107
|
+
result.job_results[klass].add_hist time, Histogram.new(klass).fetch(conn, time).reverse if minutes
|
108
|
+
time -= stride
|
77
109
|
end
|
78
110
|
end
|
79
111
|
|
80
|
-
result.marks = fetch_marks(result.starts_at..result.ends_at)
|
81
|
-
|
112
|
+
result.marks = fetch_marks(result.starts_at..result.ends_at, granularity)
|
82
113
|
result
|
83
114
|
end
|
84
115
|
|
85
|
-
class Result < Struct.new(:starts_at, :ends_at, :size, :
|
86
|
-
def initialize
|
116
|
+
class Result < Struct.new(:granularity, :starts_at, :ends_at, :size, :job_results, :marks)
|
117
|
+
def initialize(granularity = :minutely)
|
87
118
|
super
|
88
|
-
self.
|
119
|
+
self.granularity = granularity
|
89
120
|
self.marks = []
|
90
|
-
self.job_results = Hash.new { |h, k| h[k] = JobResult.new }
|
91
|
-
end
|
92
|
-
|
93
|
-
def prepend_bucket(time)
|
94
|
-
buckets.unshift time.strftime("%H:%M")
|
95
|
-
self.ends_at ||= time
|
96
|
-
self.starts_at = time
|
121
|
+
self.job_results = Hash.new { |h, k| h[k] = JobResult.new(granularity) }
|
97
122
|
end
|
98
123
|
end
|
99
124
|
|
100
|
-
class JobResult < Struct.new(:series, :hist, :totals)
|
101
|
-
def initialize
|
125
|
+
class JobResult < Struct.new(:granularity, :series, :hist, :totals)
|
126
|
+
def initialize(granularity = :minutely)
|
102
127
|
super
|
128
|
+
self.granularity = granularity
|
103
129
|
self.series = Hash.new { |h, k| h[k] = Hash.new(0) }
|
104
130
|
self.hist = Hash.new { |h, k| h[k] = [] }
|
105
131
|
self.totals = Hash.new(0)
|
@@ -107,14 +133,14 @@ module Sidekiq
|
|
107
133
|
|
108
134
|
def add_metric(metric, time, value)
|
109
135
|
totals[metric] += value
|
110
|
-
series[metric][
|
136
|
+
series[metric][Query.bkt_time_s(time, granularity)] += value
|
111
137
|
|
112
138
|
# Include timing measurements in seconds for convenience
|
113
139
|
add_metric("s", time, value / 1000.0) if metric == "ms"
|
114
140
|
end
|
115
141
|
|
116
142
|
def add_hist(time, hist_result)
|
117
|
-
hist[
|
143
|
+
hist[Query.bkt_time_s(time, granularity)] = hist_result
|
118
144
|
end
|
119
145
|
|
120
146
|
def total_avg(metric = "ms")
|
@@ -131,22 +157,24 @@ module Sidekiq
|
|
131
157
|
end
|
132
158
|
end
|
133
159
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
160
|
+
MarkResult = Struct.new(:time, :label, :bucket)
|
161
|
+
|
162
|
+
def self.bkt_time_s(time, granularity)
|
163
|
+
# truncate time to ten minutes ("8:40", not "8:43") or one minute
|
164
|
+
truncation = (granularity == :hourly) ? 600 : 60
|
165
|
+
Time.at(time.to_i - time.to_i % truncation).utc.iso8601
|
138
166
|
end
|
139
167
|
|
140
168
|
private
|
141
169
|
|
142
|
-
def fetch_marks(time_range)
|
170
|
+
def fetch_marks(time_range, granularity)
|
143
171
|
[].tap do |result|
|
144
172
|
marks = @pool.with { |c| c.hgetall("#{@time.strftime("%Y%m%d")}-marks") }
|
145
173
|
|
146
174
|
marks.each do |timestamp, label|
|
147
175
|
time = Time.parse(timestamp)
|
148
176
|
if time_range.cover? time
|
149
|
-
result << MarkResult.new(time, label)
|
177
|
+
result << MarkResult.new(time, label, Query.bkt_time_s(time, granularity))
|
150
178
|
end
|
151
179
|
end
|
152
180
|
end
|
@@ -25,7 +25,10 @@ module Sidekiq
|
|
25
25
|
#
|
26
26
|
# To store this data, we use Redis' BITFIELD command to store unsigned 16-bit counters
|
27
27
|
# per bucket per klass per minute. It's unlikely that most people will be executing more
|
28
|
-
# than 1000 job/sec for a full minute of a specific type.
|
28
|
+
# than 1000 job/sec for a full minute of a specific type (i.e. overflow 65,536).
|
29
|
+
#
|
30
|
+
# Histograms are only stored at the fine-grained level, they are not rolled up
|
31
|
+
# for longer-term buckets.
|
29
32
|
class Histogram
|
30
33
|
include Enumerable
|
31
34
|
|
@@ -19,13 +19,13 @@ module Sidekiq
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def track(queue, klass)
|
22
|
-
start =
|
22
|
+
start = mono_ms
|
23
23
|
time_ms = 0
|
24
24
|
begin
|
25
25
|
begin
|
26
26
|
yield
|
27
27
|
ensure
|
28
|
-
finish =
|
28
|
+
finish = mono_ms
|
29
29
|
time_ms = finish - start
|
30
30
|
end
|
31
31
|
# We don't track time for failed jobs as they can have very unpredictable
|
@@ -51,7 +51,7 @@ module Sidekiq
|
|
51
51
|
end
|
52
52
|
|
53
53
|
# LONG_TERM = 90 * 24 * 60 * 60
|
54
|
-
|
54
|
+
MID_TERM = 3 * 24 * 60 * 60
|
55
55
|
SHORT_TERM = 8 * 60 * 60
|
56
56
|
|
57
57
|
def flush(time = Time.now)
|
@@ -62,8 +62,10 @@ module Sidekiq
|
|
62
62
|
|
63
63
|
now = time.utc
|
64
64
|
# nowdate = now.strftime("%Y%m%d")
|
65
|
-
#
|
66
|
-
|
65
|
+
# "250214|8:4" is the 10 minute bucket for Feb 14 2025, 08:43
|
66
|
+
nowmid = now.strftime("%y%m%d|%-H:%M")[0..-2]
|
67
|
+
# "250214|8:43" is the 1 minute bucket for Feb 14 2025, 08:43
|
68
|
+
nowshort = now.strftime("%y%m%d|%-H:%M")
|
67
69
|
count = 0
|
68
70
|
|
69
71
|
redis do |conn|
|
@@ -81,8 +83,8 @@ module Sidekiq
|
|
81
83
|
# daily or hourly rollups.
|
82
84
|
[
|
83
85
|
# ["j", jobs, nowdate, LONG_TERM],
|
84
|
-
|
85
|
-
["j", jobs,
|
86
|
+
["j", jobs, nowmid, MID_TERM],
|
87
|
+
["j", jobs, nowshort, SHORT_TERM]
|
86
88
|
].each do |prefix, data, bucket, ttl|
|
87
89
|
conn.pipelined do |xa|
|
88
90
|
stats = "#{prefix}|#{bucket}"
|
data/lib/sidekiq/version.rb
CHANGED
data/lib/sidekiq/web/action.rb
CHANGED
@@ -33,6 +33,10 @@ module Sidekiq
|
|
33
33
|
throw :halt, [302, {"Location" => url}, []]
|
34
34
|
end
|
35
35
|
|
36
|
+
def header(key, value)
|
37
|
+
env["response_headers"][key] = value
|
38
|
+
end
|
39
|
+
|
36
40
|
# internal redirect
|
37
41
|
def redirect(location)
|
38
42
|
throw :halt, [302, {"Location" => "#{request.base_url}#{location}"}, []]
|
@@ -29,10 +29,13 @@ module Sidekiq
|
|
29
29
|
].join("; ").freeze
|
30
30
|
|
31
31
|
METRICS_PERIODS = {
|
32
|
-
"1h" => 60,
|
33
|
-
"2h" => 120,
|
34
|
-
"4h" => 240,
|
35
|
-
"8h" => 480
|
32
|
+
"1h" => {minutes: 60},
|
33
|
+
"2h" => {minutes: 120},
|
34
|
+
"4h" => {minutes: 240},
|
35
|
+
"8h" => {minutes: 480},
|
36
|
+
"24h" => {hours: 24},
|
37
|
+
"48h" => {hours: 48},
|
38
|
+
"72h" => {hours: 72}
|
36
39
|
}
|
37
40
|
|
38
41
|
def initialize(inst)
|
@@ -63,21 +66,26 @@ module Sidekiq
|
|
63
66
|
class_filter = (x.nil? || x == "") ? nil : Regexp.new(Regexp.escape(x), Regexp::IGNORECASE)
|
64
67
|
|
65
68
|
q = Sidekiq::Metrics::Query.new
|
66
|
-
@period = h(
|
69
|
+
@period = h(url_params("period") || "1h")
|
67
70
|
@periods = METRICS_PERIODS
|
68
|
-
|
69
|
-
@query_result = q.top_jobs(
|
71
|
+
args = @periods.fetch(@period, @periods.values.first)
|
72
|
+
@query_result = q.top_jobs(**args.merge(class_filter: class_filter))
|
70
73
|
|
74
|
+
header "refresh", 60 if @period == "1h"
|
71
75
|
erb(:metrics)
|
72
76
|
end
|
73
77
|
|
74
78
|
get "/metrics/:name" do
|
75
79
|
@name = route_params(:name)
|
76
|
-
@period = h(
|
80
|
+
@period = h(url_params("period") || "1h")
|
81
|
+
# Periods larger than 8 hours are not supported for histogram chart
|
82
|
+
@period = "8h" if @period.to_i > 8
|
83
|
+
@periods = METRICS_PERIODS.reject { |k, v| k.to_i > 8 }
|
84
|
+
args = @periods.fetch(@period, @periods.values.first)
|
77
85
|
q = Sidekiq::Metrics::Query.new
|
78
|
-
@
|
79
|
-
|
80
|
-
|
86
|
+
@query_result = q.for_job(@name, **args)
|
87
|
+
|
88
|
+
header "refresh", 60 if @period == "1h"
|
81
89
|
erb(:metrics_for_job)
|
82
90
|
end
|
83
91
|
|
@@ -399,6 +407,14 @@ module Sidekiq
|
|
399
407
|
action = match(env)
|
400
408
|
return [404, {"content-type" => "text/plain", "x-cascade" => "pass"}, ["Not Found"]] unless action
|
401
409
|
|
410
|
+
headers = {
|
411
|
+
"content-type" => "text/html",
|
412
|
+
"cache-control" => "private, no-store",
|
413
|
+
"content-language" => action.locale,
|
414
|
+
"content-security-policy" => process_csp(env, CSP_HEADER_TEMPLATE),
|
415
|
+
"x-content-type-options" => "nosniff"
|
416
|
+
}
|
417
|
+
env["response_headers"] = headers
|
402
418
|
resp = catch(:halt) do
|
403
419
|
Thread.current[:sidekiq_redis_pool] = env[:redis_pool]
|
404
420
|
action.instance_exec env, &action.block
|
@@ -412,15 +428,8 @@ module Sidekiq
|
|
412
428
|
resp
|
413
429
|
else
|
414
430
|
# rendered content goes here
|
415
|
-
headers = {
|
416
|
-
"content-type" => "text/html",
|
417
|
-
"cache-control" => "private, no-store",
|
418
|
-
"content-language" => action.locale,
|
419
|
-
"content-security-policy" => process_csp(env, CSP_HEADER_TEMPLATE),
|
420
|
-
"x-content-type-options" => "nosniff"
|
421
|
-
}
|
422
431
|
# we'll let Rack calculate Content-Length for us.
|
423
|
-
[200,
|
432
|
+
[200, env["response_headers"], [resp]]
|
424
433
|
end
|
425
434
|
end
|
426
435
|
|
data/lib/sidekiq/web/helpers.rb
CHANGED
@@ -136,7 +136,7 @@ module Sidekiq
|
|
136
136
|
|
137
137
|
def display_tags(job, within = "retries")
|
138
138
|
job.tags.map { |tag|
|
139
|
-
"<span class='label label-info jobtag'>#{filter_link(tag, within)}</span>"
|
139
|
+
"<span class='label label-info jobtag jobtag-#{Rack::Utils.escape_html(tag)}'>#{filter_link(tag, within)}</span>"
|
140
140
|
}.join(" ")
|
141
141
|
end
|
142
142
|
|
data/lib/sidekiq.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "sidekiq/version"
|
4
|
-
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.
|
4
|
+
fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 3.2.0." if RUBY_PLATFORM != "java" && Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.2.0")
|
5
5
|
|
6
6
|
begin
|
7
7
|
require "sidekiq-ent/version"
|
@@ -1,6 +1,8 @@
|
|
1
1
|
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
2
|
-
Chart.defaults.borderColor = "
|
3
|
-
Chart.defaults.color = "
|
2
|
+
Chart.defaults.borderColor = "#333";
|
3
|
+
Chart.defaults.color = "#aaa";
|
4
|
+
// Chart.defaults.borderColor = "oklch(22% 0.01 256)";
|
5
|
+
// Chart.defaults.color = "oklch(65% 0.01 256)";
|
4
6
|
}
|
5
7
|
|
6
8
|
class Colors {
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*!
|
2
|
+
* chartjs-adapter-date-fns v3.0.0
|
3
|
+
* https://www.chartjs.org
|
4
|
+
* (c) 2022 chartjs-adapter-date-fns Contributors
|
5
|
+
* Released under the MIT license
|
6
|
+
*/
|
7
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(require("chart.js")):"function"==typeof define&&define.amd?define(["chart.js"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Chart)}(this,(function(t){"use strict";function e(t){if(null===t||!0===t||!1===t)return NaN;var e=Number(t);return isNaN(e)?e:e<0?Math.ceil(e):Math.floor(e)}function r(t,e){if(e.length<t)throw new TypeError(t+" argument"+(t>1?"s":"")+" required, but only "+e.length+" present")}function n(t){r(1,arguments);var e=Object.prototype.toString.call(t);return t instanceof Date||"object"==typeof t&&"[object Date]"===e?new Date(t.getTime()):"number"==typeof t||"[object Number]"===e?new Date(t):("string"!=typeof t&&"[object String]"!==e||"undefined"==typeof console||(console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as date arguments. Please use `parseISO` to parse strings. See: https://git.io/fjule"),console.warn((new Error).stack)),new Date(NaN))}function a(t,a){r(2,arguments);var i=n(t),o=e(a);return isNaN(o)?new Date(NaN):o?(i.setDate(i.getDate()+o),i):i}function i(t,a){r(2,arguments);var i=n(t),o=e(a);if(isNaN(o))return new Date(NaN);if(!o)return i;var u=i.getDate(),s=new Date(i.getTime());s.setMonth(i.getMonth()+o+1,0);var c=s.getDate();return u>=c?s:(i.setFullYear(s.getFullYear(),s.getMonth(),u),i)}function o(t,a){r(2,arguments);var i=n(t).getTime(),o=e(a);return new Date(i+o)}var u=36e5;function s(t,a){r(1,arguments);var i=a||{},o=i.locale,u=o&&o.options&&o.options.weekStartsOn,s=null==u?0:e(u),c=null==i.weekStartsOn?s:e(i.weekStartsOn);if(!(c>=0&&c<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var d=n(t),l=d.getDay(),f=(l<c?7:0)+l-c;return d.setDate(d.getDate()-f),d.setHours(0,0,0,0),d}function c(t){var e=new Date(Date.UTC(t.getFullYear(),t.getMonth(),t.getDate(),t.getHours(),t.getMinutes(),t.getSeconds(),t.getMilliseconds()));return e.setUTCFullYear(t.getFullYear()),t.getTime()-e.getTime()}function d(t){r(1,arguments);var e=n(t);return e.setHours(0,0,0,0),e}var l=864e5;function f(t,e){r(2,arguments);var n=d(t),a=d(e),i=n.getTime()-c(n),o=a.getTime()-c(a);return Math.round((i-o)/l)}function h(t,e){r(2,arguments);var a=n(t),i=n(e),o=a.getTime()-i.getTime();return o<0?-1:o>0?1:o}function m(t){r(1,arguments);var e=n(t);return!isNaN(e)}function w(t,e){r(2,arguments);var a=n(t),i=n(e),o=a.getFullYear()-i.getFullYear(),u=a.getMonth()-i.getMonth();return 12*o+u}function g(t,e){r(2,arguments);var a=n(t),i=n(e);return a.getFullYear()-i.getFullYear()}function v(t,e){var r=t.getFullYear()-e.getFullYear()||t.getMonth()-e.getMonth()||t.getDate()-e.getDate()||t.getHours()-e.getHours()||t.getMinutes()-e.getMinutes()||t.getSeconds()-e.getSeconds()||t.getMilliseconds()-e.getMilliseconds();return r<0?-1:r>0?1:r}function y(t,e){r(2,arguments);var a=n(t),i=n(e),o=v(a,i),u=Math.abs(f(a,i));a.setDate(a.getDate()-o*u);var s=v(a,i)===-o,c=o*(u-s);return 0===c?0:c}function b(t,e){r(2,arguments);var a=n(t),i=n(e);return a.getTime()-i.getTime()}var T=36e5;function p(t){r(1,arguments);var e=n(t);return e.setHours(23,59,59,999),e}function C(t){r(1,arguments);var e=n(t),a=e.getMonth();return e.setFullYear(e.getFullYear(),a+1,0),e.setHours(23,59,59,999),e}function M(t){r(1,arguments);var e=n(t);return p(e).getTime()===C(e).getTime()}function D(t,e){r(2,arguments);var a,i=n(t),o=n(e),u=h(i,o),s=Math.abs(w(i,o));if(s<1)a=0;else{1===i.getMonth()&&i.getDate()>27&&i.setDate(30),i.setMonth(i.getMonth()-u*s);var c=h(i,o)===-u;M(n(t))&&1===s&&1===h(t,o)&&(c=!1),a=u*(s-c)}return 0===a?0:a}var x={lessThanXSeconds:{one:"less than a second",other:"less than {{count}} seconds"},xSeconds:{one:"1 second",other:"{{count}} seconds"},halfAMinute:"half a minute",lessThanXMinutes:{one:"less than a minute",other:"less than {{count}} minutes"},xMinutes:{one:"1 minute",other:"{{count}} minutes"},aboutXHours:{one:"about 1 hour",other:"about {{count}} hours"},xHours:{one:"1 hour",other:"{{count}} hours"},xDays:{one:"1 day",other:"{{count}} days"},aboutXWeeks:{one:"about 1 week",other:"about {{count}} weeks"},xWeeks:{one:"1 week",other:"{{count}} weeks"},aboutXMonths:{one:"about 1 month",other:"about {{count}} months"},xMonths:{one:"1 month",other:"{{count}} months"},aboutXYears:{one:"about 1 year",other:"about {{count}} years"},xYears:{one:"1 year",other:"{{count}} years"},overXYears:{one:"over 1 year",other:"over {{count}} years"},almostXYears:{one:"almost 1 year",other:"almost {{count}} years"}};function k(t){return function(e){var r=e||{},n=r.width?String(r.width):t.defaultWidth;return t.formats[n]||t.formats[t.defaultWidth]}}var U={date:k({formats:{full:"EEEE, MMMM do, y",long:"MMMM do, y",medium:"MMM d, y",short:"MM/dd/yyyy"},defaultWidth:"full"}),time:k({formats:{full:"h:mm:ss a zzzz",long:"h:mm:ss a z",medium:"h:mm:ss a",short:"h:mm a"},defaultWidth:"full"}),dateTime:k({formats:{full:"{{date}} 'at' {{time}}",long:"{{date}} 'at' {{time}}",medium:"{{date}}, {{time}}",short:"{{date}}, {{time}}"},defaultWidth:"full"})},Y={lastWeek:"'last' eeee 'at' p",yesterday:"'yesterday at' p",today:"'today at' p",tomorrow:"'tomorrow at' p",nextWeek:"eeee 'at' p",other:"P"};function N(t){return function(e,r){var n,a=r||{};if("formatting"===(a.context?String(a.context):"standalone")&&t.formattingValues){var i=t.defaultFormattingWidth||t.defaultWidth,o=a.width?String(a.width):i;n=t.formattingValues[o]||t.formattingValues[i]}else{var u=t.defaultWidth,s=a.width?String(a.width):t.defaultWidth;n=t.values[s]||t.values[u]}return n[t.argumentCallback?t.argumentCallback(e):e]}}function S(t){return function(e,r){var n=String(e),a=r||{},i=a.width,o=i&&t.matchPatterns[i]||t.matchPatterns[t.defaultMatchWidth],u=n.match(o);if(!u)return null;var s,c=u[0],d=i&&t.parsePatterns[i]||t.parsePatterns[t.defaultParseWidth];return s="[object Array]"===Object.prototype.toString.call(d)?function(t,e){for(var r=0;r<t.length;r++)if(e(t[r]))return r}(d,(function(t){return t.test(c)})):function(t,e){for(var r in t)if(t.hasOwnProperty(r)&&e(t[r]))return r}(d,(function(t){return t.test(c)})),s=t.valueCallback?t.valueCallback(s):s,{value:s=a.valueCallback?a.valueCallback(s):s,rest:n.slice(c.length)}}}var P,q={code:"en-US",formatDistance:function(t,e,r){var n;return r=r||{},n="string"==typeof x[t]?x[t]:1===e?x[t].one:x[t].other.replace("{{count}}",e),r.addSuffix?r.comparison>0?"in "+n:n+" ago":n},formatLong:U,formatRelative:function(t,e,r,n){return Y[t]},localize:{ordinalNumber:function(t,e){var r=Number(t),n=r%100;if(n>20||n<10)switch(n%10){case 1:return r+"st";case 2:return r+"nd";case 3:return r+"rd"}return r+"th"},era:N({values:{narrow:["B","A"],abbreviated:["BC","AD"],wide:["Before Christ","Anno Domini"]},defaultWidth:"wide"}),quarter:N({values:{narrow:["1","2","3","4"],abbreviated:["Q1","Q2","Q3","Q4"],wide:["1st quarter","2nd quarter","3rd quarter","4th quarter"]},defaultWidth:"wide",argumentCallback:function(t){return Number(t)-1}}),month:N({values:{narrow:["J","F","M","A","M","J","J","A","S","O","N","D"],abbreviated:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],wide:["January","February","March","April","May","June","July","August","September","October","November","December"]},defaultWidth:"wide"}),day:N({values:{narrow:["S","M","T","W","T","F","S"],short:["Su","Mo","Tu","We","Th","Fr","Sa"],abbreviated:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],wide:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"]},defaultWidth:"wide"}),dayPeriod:N({values:{narrow:{am:"a",pm:"p",midnight:"mi",noon:"n",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"},abbreviated:{am:"AM",pm:"PM",midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"},wide:{am:"a.m.",pm:"p.m.",midnight:"midnight",noon:"noon",morning:"morning",afternoon:"afternoon",evening:"evening",night:"night"}},defaultWidth:"wide",formattingValues:{narrow:{am:"a",pm:"p",midnight:"mi",noon:"n",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"},abbreviated:{am:"AM",pm:"PM",midnight:"midnight",noon:"noon",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"},wide:{am:"a.m.",pm:"p.m.",midnight:"midnight",noon:"noon",morning:"in the morning",afternoon:"in the afternoon",evening:"in the evening",night:"at night"}},defaultFormattingWidth:"wide"})},match:{ordinalNumber:(P={matchPattern:/^(\d+)(th|st|nd|rd)?/i,parsePattern:/\d+/i,valueCallback:function(t){return parseInt(t,10)}},function(t,e){var r=String(t),n=e||{},a=r.match(P.matchPattern);if(!a)return null;var i=a[0],o=r.match(P.parsePattern);if(!o)return null;var u=P.valueCallback?P.valueCallback(o[0]):o[0];return{value:u=n.valueCallback?n.valueCallback(u):u,rest:r.slice(i.length)}}),era:S({matchPatterns:{narrow:/^(b|a)/i,abbreviated:/^(b\.?\s?c\.?|b\.?\s?c\.?\s?e\.?|a\.?\s?d\.?|c\.?\s?e\.?)/i,wide:/^(before christ|before common era|anno domini|common era)/i},defaultMatchWidth:"wide",parsePatterns:{any:[/^b/i,/^(a|c)/i]},defaultParseWidth:"any"}),quarter:S({matchPatterns:{narrow:/^[1234]/i,abbreviated:/^q[1234]/i,wide:/^[1234](th|st|nd|rd)? quarter/i},defaultMatchWidth:"wide",parsePatterns:{any:[/1/i,/2/i,/3/i,/4/i]},defaultParseWidth:"any",valueCallback:function(t){return t+1}}),month:S({matchPatterns:{narrow:/^[jfmasond]/i,abbreviated:/^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i,wide:/^(january|february|march|april|may|june|july|august|september|october|november|december)/i},defaultMatchWidth:"wide",parsePatterns:{narrow:[/^j/i,/^f/i,/^m/i,/^a/i,/^m/i,/^j/i,/^j/i,/^a/i,/^s/i,/^o/i,/^n/i,/^d/i],any:[/^ja/i,/^f/i,/^mar/i,/^ap/i,/^may/i,/^jun/i,/^jul/i,/^au/i,/^s/i,/^o/i,/^n/i,/^d/i]},defaultParseWidth:"any"}),day:S({matchPatterns:{narrow:/^[smtwf]/i,short:/^(su|mo|tu|we|th|fr|sa)/i,abbreviated:/^(sun|mon|tue|wed|thu|fri|sat)/i,wide:/^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i},defaultMatchWidth:"wide",parsePatterns:{narrow:[/^s/i,/^m/i,/^t/i,/^w/i,/^t/i,/^f/i,/^s/i],any:[/^su/i,/^m/i,/^tu/i,/^w/i,/^th/i,/^f/i,/^sa/i]},defaultParseWidth:"any"}),dayPeriod:S({matchPatterns:{narrow:/^(a|p|mi|n|(in the|at) (morning|afternoon|evening|night))/i,any:/^([ap]\.?\s?m\.?|midnight|noon|(in the|at) (morning|afternoon|evening|night))/i},defaultMatchWidth:"any",parsePatterns:{any:{am:/^a/i,pm:/^p/i,midnight:/^mi/i,noon:/^no/i,morning:/morning/i,afternoon:/afternoon/i,evening:/evening/i,night:/night/i}},defaultParseWidth:"any"})},options:{weekStartsOn:0,firstWeekContainsDate:1}};function H(t,n){r(2,arguments);var a=e(n);return o(t,-a)}function E(t,e){for(var r=t<0?"-":"",n=Math.abs(t).toString();n.length<e;)n="0"+n;return r+n}var O={y:function(t,e){var r=t.getUTCFullYear(),n=r>0?r:1-r;return E("yy"===e?n%100:n,e.length)},M:function(t,e){var r=t.getUTCMonth();return"M"===e?String(r+1):E(r+1,2)},d:function(t,e){return E(t.getUTCDate(),e.length)},a:function(t,e){var r=t.getUTCHours()/12>=1?"pm":"am";switch(e){case"a":case"aa":return r.toUpperCase();case"aaa":return r;case"aaaaa":return r[0];default:return"am"===r?"a.m.":"p.m."}},h:function(t,e){return E(t.getUTCHours()%12||12,e.length)},H:function(t,e){return E(t.getUTCHours(),e.length)},m:function(t,e){return E(t.getUTCMinutes(),e.length)},s:function(t,e){return E(t.getUTCSeconds(),e.length)},S:function(t,e){var r=e.length,n=t.getUTCMilliseconds();return E(Math.floor(n*Math.pow(10,r-3)),e.length)}},F=864e5;function W(t){r(1,arguments);var e=1,a=n(t),i=a.getUTCDay(),o=(i<e?7:0)+i-e;return a.setUTCDate(a.getUTCDate()-o),a.setUTCHours(0,0,0,0),a}function L(t){r(1,arguments);var e=n(t),a=e.getUTCFullYear(),i=new Date(0);i.setUTCFullYear(a+1,0,4),i.setUTCHours(0,0,0,0);var o=W(i),u=new Date(0);u.setUTCFullYear(a,0,4),u.setUTCHours(0,0,0,0);var s=W(u);return e.getTime()>=o.getTime()?a+1:e.getTime()>=s.getTime()?a:a-1}function Q(t){r(1,arguments);var e=L(t),n=new Date(0);n.setUTCFullYear(e,0,4),n.setUTCHours(0,0,0,0);var a=W(n);return a}var R=6048e5;function I(t){r(1,arguments);var e=n(t),a=W(e).getTime()-Q(e).getTime();return Math.round(a/R)+1}function G(t,a){r(1,arguments);var i=a||{},o=i.locale,u=o&&o.options&&o.options.weekStartsOn,s=null==u?0:e(u),c=null==i.weekStartsOn?s:e(i.weekStartsOn);if(!(c>=0&&c<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var d=n(t),l=d.getUTCDay(),f=(l<c?7:0)+l-c;return d.setUTCDate(d.getUTCDate()-f),d.setUTCHours(0,0,0,0),d}function X(t,a){r(1,arguments);var i=n(t,a),o=i.getUTCFullYear(),u=a||{},s=u.locale,c=s&&s.options&&s.options.firstWeekContainsDate,d=null==c?1:e(c),l=null==u.firstWeekContainsDate?d:e(u.firstWeekContainsDate);if(!(l>=1&&l<=7))throw new RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var f=new Date(0);f.setUTCFullYear(o+1,0,l),f.setUTCHours(0,0,0,0);var h=G(f,a),m=new Date(0);m.setUTCFullYear(o,0,l),m.setUTCHours(0,0,0,0);var w=G(m,a);return i.getTime()>=h.getTime()?o+1:i.getTime()>=w.getTime()?o:o-1}function j(t,n){r(1,arguments);var a=n||{},i=a.locale,o=i&&i.options&&i.options.firstWeekContainsDate,u=null==o?1:e(o),s=null==a.firstWeekContainsDate?u:e(a.firstWeekContainsDate),c=X(t,n),d=new Date(0);d.setUTCFullYear(c,0,s),d.setUTCHours(0,0,0,0);var l=G(d,n);return l}var B=6048e5;function z(t,e){r(1,arguments);var a=n(t),i=G(a,e).getTime()-j(a,e).getTime();return Math.round(i/B)+1}var A="midnight",Z="noon",K="morning",$="afternoon",_="evening",J="night",V={G:function(t,e,r){var n=t.getUTCFullYear()>0?1:0;switch(e){case"G":case"GG":case"GGG":return r.era(n,{width:"abbreviated"});case"GGGGG":return r.era(n,{width:"narrow"});default:return r.era(n,{width:"wide"})}},y:function(t,e,r){if("yo"===e){var n=t.getUTCFullYear(),a=n>0?n:1-n;return r.ordinalNumber(a,{unit:"year"})}return O.y(t,e)},Y:function(t,e,r,n){var a=X(t,n),i=a>0?a:1-a;return"YY"===e?E(i%100,2):"Yo"===e?r.ordinalNumber(i,{unit:"year"}):E(i,e.length)},R:function(t,e){return E(L(t),e.length)},u:function(t,e){return E(t.getUTCFullYear(),e.length)},Q:function(t,e,r){var n=Math.ceil((t.getUTCMonth()+1)/3);switch(e){case"Q":return String(n);case"QQ":return E(n,2);case"Qo":return r.ordinalNumber(n,{unit:"quarter"});case"QQQ":return r.quarter(n,{width:"abbreviated",context:"formatting"});case"QQQQQ":return r.quarter(n,{width:"narrow",context:"formatting"});default:return r.quarter(n,{width:"wide",context:"formatting"})}},q:function(t,e,r){var n=Math.ceil((t.getUTCMonth()+1)/3);switch(e){case"q":return String(n);case"qq":return E(n,2);case"qo":return r.ordinalNumber(n,{unit:"quarter"});case"qqq":return r.quarter(n,{width:"abbreviated",context:"standalone"});case"qqqqq":return r.quarter(n,{width:"narrow",context:"standalone"});default:return r.quarter(n,{width:"wide",context:"standalone"})}},M:function(t,e,r){var n=t.getUTCMonth();switch(e){case"M":case"MM":return O.M(t,e);case"Mo":return r.ordinalNumber(n+1,{unit:"month"});case"MMM":return r.month(n,{width:"abbreviated",context:"formatting"});case"MMMMM":return r.month(n,{width:"narrow",context:"formatting"});default:return r.month(n,{width:"wide",context:"formatting"})}},L:function(t,e,r){var n=t.getUTCMonth();switch(e){case"L":return String(n+1);case"LL":return E(n+1,2);case"Lo":return r.ordinalNumber(n+1,{unit:"month"});case"LLL":return r.month(n,{width:"abbreviated",context:"standalone"});case"LLLLL":return r.month(n,{width:"narrow",context:"standalone"});default:return r.month(n,{width:"wide",context:"standalone"})}},w:function(t,e,r,n){var a=z(t,n);return"wo"===e?r.ordinalNumber(a,{unit:"week"}):E(a,e.length)},I:function(t,e,r){var n=I(t);return"Io"===e?r.ordinalNumber(n,{unit:"week"}):E(n,e.length)},d:function(t,e,r){return"do"===e?r.ordinalNumber(t.getUTCDate(),{unit:"date"}):O.d(t,e)},D:function(t,e,a){var i=function(t){r(1,arguments);var e=n(t),a=e.getTime();e.setUTCMonth(0,1),e.setUTCHours(0,0,0,0);var i=e.getTime(),o=a-i;return Math.floor(o/F)+1}(t);return"Do"===e?a.ordinalNumber(i,{unit:"dayOfYear"}):E(i,e.length)},E:function(t,e,r){var n=t.getUTCDay();switch(e){case"E":case"EE":case"EEE":return r.day(n,{width:"abbreviated",context:"formatting"});case"EEEEE":return r.day(n,{width:"narrow",context:"formatting"});case"EEEEEE":return r.day(n,{width:"short",context:"formatting"});default:return r.day(n,{width:"wide",context:"formatting"})}},e:function(t,e,r,n){var a=t.getUTCDay(),i=(a-n.weekStartsOn+8)%7||7;switch(e){case"e":return String(i);case"ee":return E(i,2);case"eo":return r.ordinalNumber(i,{unit:"day"});case"eee":return r.day(a,{width:"abbreviated",context:"formatting"});case"eeeee":return r.day(a,{width:"narrow",context:"formatting"});case"eeeeee":return r.day(a,{width:"short",context:"formatting"});default:return r.day(a,{width:"wide",context:"formatting"})}},c:function(t,e,r,n){var a=t.getUTCDay(),i=(a-n.weekStartsOn+8)%7||7;switch(e){case"c":return String(i);case"cc":return E(i,e.length);case"co":return r.ordinalNumber(i,{unit:"day"});case"ccc":return r.day(a,{width:"abbreviated",context:"standalone"});case"ccccc":return r.day(a,{width:"narrow",context:"standalone"});case"cccccc":return r.day(a,{width:"short",context:"standalone"});default:return r.day(a,{width:"wide",context:"standalone"})}},i:function(t,e,r){var n=t.getUTCDay(),a=0===n?7:n;switch(e){case"i":return String(a);case"ii":return E(a,e.length);case"io":return r.ordinalNumber(a,{unit:"day"});case"iii":return r.day(n,{width:"abbreviated",context:"formatting"});case"iiiii":return r.day(n,{width:"narrow",context:"formatting"});case"iiiiii":return r.day(n,{width:"short",context:"formatting"});default:return r.day(n,{width:"wide",context:"formatting"})}},a:function(t,e,r){var n=t.getUTCHours()/12>=1?"pm":"am";switch(e){case"a":case"aa":return r.dayPeriod(n,{width:"abbreviated",context:"formatting"});case"aaa":return r.dayPeriod(n,{width:"abbreviated",context:"formatting"}).toLowerCase();case"aaaaa":return r.dayPeriod(n,{width:"narrow",context:"formatting"});default:return r.dayPeriod(n,{width:"wide",context:"formatting"})}},b:function(t,e,r){var n,a=t.getUTCHours();switch(n=12===a?Z:0===a?A:a/12>=1?"pm":"am",e){case"b":case"bb":return r.dayPeriod(n,{width:"abbreviated",context:"formatting"});case"bbb":return r.dayPeriod(n,{width:"abbreviated",context:"formatting"}).toLowerCase();case"bbbbb":return r.dayPeriod(n,{width:"narrow",context:"formatting"});default:return r.dayPeriod(n,{width:"wide",context:"formatting"})}},B:function(t,e,r){var n,a=t.getUTCHours();switch(n=a>=17?_:a>=12?$:a>=4?K:J,e){case"B":case"BB":case"BBB":return r.dayPeriod(n,{width:"abbreviated",context:"formatting"});case"BBBBB":return r.dayPeriod(n,{width:"narrow",context:"formatting"});default:return r.dayPeriod(n,{width:"wide",context:"formatting"})}},h:function(t,e,r){if("ho"===e){var n=t.getUTCHours()%12;return 0===n&&(n=12),r.ordinalNumber(n,{unit:"hour"})}return O.h(t,e)},H:function(t,e,r){return"Ho"===e?r.ordinalNumber(t.getUTCHours(),{unit:"hour"}):O.H(t,e)},K:function(t,e,r){var n=t.getUTCHours()%12;return"Ko"===e?r.ordinalNumber(n,{unit:"hour"}):E(n,e.length)},k:function(t,e,r){var n=t.getUTCHours();return 0===n&&(n=24),"ko"===e?r.ordinalNumber(n,{unit:"hour"}):E(n,e.length)},m:function(t,e,r){return"mo"===e?r.ordinalNumber(t.getUTCMinutes(),{unit:"minute"}):O.m(t,e)},s:function(t,e,r){return"so"===e?r.ordinalNumber(t.getUTCSeconds(),{unit:"second"}):O.s(t,e)},S:function(t,e){return O.S(t,e)},X:function(t,e,r,n){var a=(n._originalDate||t).getTimezoneOffset();if(0===a)return"Z";switch(e){case"X":return et(a);case"XXXX":case"XX":return rt(a);default:return rt(a,":")}},x:function(t,e,r,n){var a=(n._originalDate||t).getTimezoneOffset();switch(e){case"x":return et(a);case"xxxx":case"xx":return rt(a);default:return rt(a,":")}},O:function(t,e,r,n){var a=(n._originalDate||t).getTimezoneOffset();switch(e){case"O":case"OO":case"OOO":return"GMT"+tt(a,":");default:return"GMT"+rt(a,":")}},z:function(t,e,r,n){var a=(n._originalDate||t).getTimezoneOffset();switch(e){case"z":case"zz":case"zzz":return"GMT"+tt(a,":");default:return"GMT"+rt(a,":")}},t:function(t,e,r,n){var a=n._originalDate||t;return E(Math.floor(a.getTime()/1e3),e.length)},T:function(t,e,r,n){return E((n._originalDate||t).getTime(),e.length)}};function tt(t,e){var r=t>0?"-":"+",n=Math.abs(t),a=Math.floor(n/60),i=n%60;if(0===i)return r+String(a);var o=e||"";return r+String(a)+o+E(i,2)}function et(t,e){return t%60==0?(t>0?"-":"+")+E(Math.abs(t)/60,2):rt(t,e)}function rt(t,e){var r=e||"",n=t>0?"-":"+",a=Math.abs(t);return n+E(Math.floor(a/60),2)+r+E(a%60,2)}var nt=V;function at(t,e){switch(t){case"P":return e.date({width:"short"});case"PP":return e.date({width:"medium"});case"PPP":return e.date({width:"long"});default:return e.date({width:"full"})}}function it(t,e){switch(t){case"p":return e.time({width:"short"});case"pp":return e.time({width:"medium"});case"ppp":return e.time({width:"long"});default:return e.time({width:"full"})}}var ot={p:it,P:function(t,e){var r,n=t.match(/(P+)(p+)?/),a=n[1],i=n[2];if(!i)return at(t,e);switch(a){case"P":r=e.dateTime({width:"short"});break;case"PP":r=e.dateTime({width:"medium"});break;case"PPP":r=e.dateTime({width:"long"});break;default:r=e.dateTime({width:"full"})}return r.replace("{{date}}",at(a,e)).replace("{{time}}",it(i,e))}},ut=ot,st=["D","DD"],ct=["YY","YYYY"];function dt(t){return-1!==st.indexOf(t)}function lt(t){return-1!==ct.indexOf(t)}function ft(t,e,r){if("YYYY"===t)throw new RangeError("Use `yyyy` instead of `YYYY` (in `".concat(e,"`) for formatting years to the input `").concat(r,"`; see: https://git.io/fxCyr"));if("YY"===t)throw new RangeError("Use `yy` instead of `YY` (in `".concat(e,"`) for formatting years to the input `").concat(r,"`; see: https://git.io/fxCyr"));if("D"===t)throw new RangeError("Use `d` instead of `D` (in `".concat(e,"`) for formatting days of the month to the input `").concat(r,"`; see: https://git.io/fxCyr"));if("DD"===t)throw new RangeError("Use `dd` instead of `DD` (in `".concat(e,"`) for formatting days of the month to the input `").concat(r,"`; see: https://git.io/fxCyr"))}var ht=/[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g,mt=/P+p+|P+|p+|''|'(''|[^'])+('|$)|./g,wt=/^'([^]*?)'?$/,gt=/''/g,vt=/[a-zA-Z]/;function yt(t){return t.match(wt)[1].replace(gt,"'")}function bt(t,e){if(null==t)throw new TypeError("assign requires that input parameter not be null or undefined");for(var r in e=e||{})e.hasOwnProperty(r)&&(t[r]=e[r]);return t}function Tt(t,a,i){r(2,arguments);var o=i||{},u=o.locale,s=u&&u.options&&u.options.weekStartsOn,c=null==s?0:e(s),d=null==o.weekStartsOn?c:e(o.weekStartsOn);if(!(d>=0&&d<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var l=n(t),f=e(a),h=l.getUTCDay(),m=f%7,w=(m+7)%7,g=(w<d?7:0)+f-h;return l.setUTCDate(l.getUTCDate()+g),l}var pt=/^(1[0-2]|0?\d)/,Ct=/^(3[0-1]|[0-2]?\d)/,Mt=/^(36[0-6]|3[0-5]\d|[0-2]?\d?\d)/,Dt=/^(5[0-3]|[0-4]?\d)/,xt=/^(2[0-3]|[0-1]?\d)/,kt=/^(2[0-4]|[0-1]?\d)/,Ut=/^(1[0-1]|0?\d)/,Yt=/^(1[0-2]|0?\d)/,Nt=/^[0-5]?\d/,St=/^[0-5]?\d/,Pt=/^\d/,qt=/^\d{1,2}/,Ht=/^\d{1,3}/,Et=/^\d{1,4}/,Ot=/^-?\d+/,Ft=/^-?\d/,Wt=/^-?\d{1,2}/,Lt=/^-?\d{1,3}/,Qt=/^-?\d{1,4}/,Rt=/^([+-])(\d{2})(\d{2})?|Z/,It=/^([+-])(\d{2})(\d{2})|Z/,Gt=/^([+-])(\d{2})(\d{2})((\d{2}))?|Z/,Xt=/^([+-])(\d{2}):(\d{2})|Z/,jt=/^([+-])(\d{2}):(\d{2})(:(\d{2}))?|Z/;function Bt(t,e,r){var n=e.match(t);if(!n)return null;var a=parseInt(n[0],10);return{value:r?r(a):a,rest:e.slice(n[0].length)}}function zt(t,e){var r=e.match(t);return r?"Z"===r[0]?{value:0,rest:e.slice(1)}:{value:("+"===r[1]?1:-1)*(36e5*(r[2]?parseInt(r[2],10):0)+6e4*(r[3]?parseInt(r[3],10):0)+1e3*(r[5]?parseInt(r[5],10):0)),rest:e.slice(r[0].length)}:null}function At(t,e){return Bt(Ot,t,e)}function Zt(t,e,r){switch(t){case 1:return Bt(Pt,e,r);case 2:return Bt(qt,e,r);case 3:return Bt(Ht,e,r);case 4:return Bt(Et,e,r);default:return Bt(new RegExp("^\\d{1,"+t+"}"),e,r)}}function Kt(t,e,r){switch(t){case 1:return Bt(Ft,e,r);case 2:return Bt(Wt,e,r);case 3:return Bt(Lt,e,r);case 4:return Bt(Qt,e,r);default:return Bt(new RegExp("^-?\\d{1,"+t+"}"),e,r)}}function $t(t){switch(t){case"morning":return 4;case"evening":return 17;case"pm":case"noon":case"afternoon":return 12;default:return 0}}function _t(t,e){var r,n=e>0,a=n?e:1-e;if(a<=50)r=t||100;else{var i=a+50;r=t+100*Math.floor(i/100)-(t>=i%100?100:0)}return n?r:1-r}var Jt=[31,28,31,30,31,30,31,31,30,31,30,31],Vt=[31,29,31,30,31,30,31,31,30,31,30,31];function te(t){return t%400==0||t%4==0&&t%100!=0}var ee={G:{priority:140,parse:function(t,e,r,n){switch(e){case"G":case"GG":case"GGG":return r.era(t,{width:"abbreviated"})||r.era(t,{width:"narrow"});case"GGGGG":return r.era(t,{width:"narrow"});default:return r.era(t,{width:"wide"})||r.era(t,{width:"abbreviated"})||r.era(t,{width:"narrow"})}},set:function(t,e,r,n){return e.era=r,t.setUTCFullYear(r,0,1),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["R","u","t","T"]},y:{priority:130,parse:function(t,e,r,n){var a=function(t){return{year:t,isTwoDigitYear:"yy"===e}};switch(e){case"y":return Zt(4,t,a);case"yo":return r.ordinalNumber(t,{unit:"year",valueCallback:a});default:return Zt(e.length,t,a)}},validate:function(t,e,r){return e.isTwoDigitYear||e.year>0},set:function(t,e,r,n){var a=t.getUTCFullYear();if(r.isTwoDigitYear){var i=_t(r.year,a);return t.setUTCFullYear(i,0,1),t.setUTCHours(0,0,0,0),t}var o="era"in e&&1!==e.era?1-r.year:r.year;return t.setUTCFullYear(o,0,1),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["Y","R","u","w","I","i","e","c","t","T"]},Y:{priority:130,parse:function(t,e,r,n){var a=function(t){return{year:t,isTwoDigitYear:"YY"===e}};switch(e){case"Y":return Zt(4,t,a);case"Yo":return r.ordinalNumber(t,{unit:"year",valueCallback:a});default:return Zt(e.length,t,a)}},validate:function(t,e,r){return e.isTwoDigitYear||e.year>0},set:function(t,e,r,n){var a=X(t,n);if(r.isTwoDigitYear){var i=_t(r.year,a);return t.setUTCFullYear(i,0,n.firstWeekContainsDate),t.setUTCHours(0,0,0,0),G(t,n)}var o="era"in e&&1!==e.era?1-r.year:r.year;return t.setUTCFullYear(o,0,n.firstWeekContainsDate),t.setUTCHours(0,0,0,0),G(t,n)},incompatibleTokens:["y","R","u","Q","q","M","L","I","d","D","i","t","T"]},R:{priority:130,parse:function(t,e,r,n){return Kt("R"===e?4:e.length,t)},set:function(t,e,r,n){var a=new Date(0);return a.setUTCFullYear(r,0,4),a.setUTCHours(0,0,0,0),W(a)},incompatibleTokens:["G","y","Y","u","Q","q","M","L","w","d","D","e","c","t","T"]},u:{priority:130,parse:function(t,e,r,n){return Kt("u"===e?4:e.length,t)},set:function(t,e,r,n){return t.setUTCFullYear(r,0,1),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["G","y","Y","R","w","I","i","e","c","t","T"]},Q:{priority:120,parse:function(t,e,r,n){switch(e){case"Q":case"QQ":return Zt(e.length,t);case"Qo":return r.ordinalNumber(t,{unit:"quarter"});case"QQQ":return r.quarter(t,{width:"abbreviated",context:"formatting"})||r.quarter(t,{width:"narrow",context:"formatting"});case"QQQQQ":return r.quarter(t,{width:"narrow",context:"formatting"});default:return r.quarter(t,{width:"wide",context:"formatting"})||r.quarter(t,{width:"abbreviated",context:"formatting"})||r.quarter(t,{width:"narrow",context:"formatting"})}},validate:function(t,e,r){return e>=1&&e<=4},set:function(t,e,r,n){return t.setUTCMonth(3*(r-1),1),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["Y","R","q","M","L","w","I","d","D","i","e","c","t","T"]},q:{priority:120,parse:function(t,e,r,n){switch(e){case"q":case"qq":return Zt(e.length,t);case"qo":return r.ordinalNumber(t,{unit:"quarter"});case"qqq":return r.quarter(t,{width:"abbreviated",context:"standalone"})||r.quarter(t,{width:"narrow",context:"standalone"});case"qqqqq":return r.quarter(t,{width:"narrow",context:"standalone"});default:return r.quarter(t,{width:"wide",context:"standalone"})||r.quarter(t,{width:"abbreviated",context:"standalone"})||r.quarter(t,{width:"narrow",context:"standalone"})}},validate:function(t,e,r){return e>=1&&e<=4},set:function(t,e,r,n){return t.setUTCMonth(3*(r-1),1),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["Y","R","Q","M","L","w","I","d","D","i","e","c","t","T"]},M:{priority:110,parse:function(t,e,r,n){var a=function(t){return t-1};switch(e){case"M":return Bt(pt,t,a);case"MM":return Zt(2,t,a);case"Mo":return r.ordinalNumber(t,{unit:"month",valueCallback:a});case"MMM":return r.month(t,{width:"abbreviated",context:"formatting"})||r.month(t,{width:"narrow",context:"formatting"});case"MMMMM":return r.month(t,{width:"narrow",context:"formatting"});default:return r.month(t,{width:"wide",context:"formatting"})||r.month(t,{width:"abbreviated",context:"formatting"})||r.month(t,{width:"narrow",context:"formatting"})}},validate:function(t,e,r){return e>=0&&e<=11},set:function(t,e,r,n){return t.setUTCMonth(r,1),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["Y","R","q","Q","L","w","I","D","i","e","c","t","T"]},L:{priority:110,parse:function(t,e,r,n){var a=function(t){return t-1};switch(e){case"L":return Bt(pt,t,a);case"LL":return Zt(2,t,a);case"Lo":return r.ordinalNumber(t,{unit:"month",valueCallback:a});case"LLL":return r.month(t,{width:"abbreviated",context:"standalone"})||r.month(t,{width:"narrow",context:"standalone"});case"LLLLL":return r.month(t,{width:"narrow",context:"standalone"});default:return r.month(t,{width:"wide",context:"standalone"})||r.month(t,{width:"abbreviated",context:"standalone"})||r.month(t,{width:"narrow",context:"standalone"})}},validate:function(t,e,r){return e>=0&&e<=11},set:function(t,e,r,n){return t.setUTCMonth(r,1),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["Y","R","q","Q","M","w","I","D","i","e","c","t","T"]},w:{priority:100,parse:function(t,e,r,n){switch(e){case"w":return Bt(Dt,t);case"wo":return r.ordinalNumber(t,{unit:"week"});default:return Zt(e.length,t)}},validate:function(t,e,r){return e>=1&&e<=53},set:function(t,a,i,o){return G(function(t,a,i){r(2,arguments);var o=n(t),u=e(a),s=z(o,i)-u;return o.setUTCDate(o.getUTCDate()-7*s),o}(t,i,o),o)},incompatibleTokens:["y","R","u","q","Q","M","L","I","d","D","i","t","T"]},I:{priority:100,parse:function(t,e,r,n){switch(e){case"I":return Bt(Dt,t);case"Io":return r.ordinalNumber(t,{unit:"week"});default:return Zt(e.length,t)}},validate:function(t,e,r){return e>=1&&e<=53},set:function(t,a,i,o){return W(function(t,a){r(2,arguments);var i=n(t),o=e(a),u=I(i)-o;return i.setUTCDate(i.getUTCDate()-7*u),i}(t,i,o),o)},incompatibleTokens:["y","Y","u","q","Q","M","L","w","d","D","e","c","t","T"]},d:{priority:90,subPriority:1,parse:function(t,e,r,n){switch(e){case"d":return Bt(Ct,t);case"do":return r.ordinalNumber(t,{unit:"date"});default:return Zt(e.length,t)}},validate:function(t,e,r){var n=te(t.getUTCFullYear()),a=t.getUTCMonth();return n?e>=1&&e<=Vt[a]:e>=1&&e<=Jt[a]},set:function(t,e,r,n){return t.setUTCDate(r),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["Y","R","q","Q","w","I","D","i","e","c","t","T"]},D:{priority:90,subPriority:1,parse:function(t,e,r,n){switch(e){case"D":case"DD":return Bt(Mt,t);case"Do":return r.ordinalNumber(t,{unit:"date"});default:return Zt(e.length,t)}},validate:function(t,e,r){return te(t.getUTCFullYear())?e>=1&&e<=366:e>=1&&e<=365},set:function(t,e,r,n){return t.setUTCMonth(0,r),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["Y","R","q","Q","M","L","w","I","d","E","i","e","c","t","T"]},E:{priority:90,parse:function(t,e,r,n){switch(e){case"E":case"EE":case"EEE":return r.day(t,{width:"abbreviated",context:"formatting"})||r.day(t,{width:"short",context:"formatting"})||r.day(t,{width:"narrow",context:"formatting"});case"EEEEE":return r.day(t,{width:"narrow",context:"formatting"});case"EEEEEE":return r.day(t,{width:"short",context:"formatting"})||r.day(t,{width:"narrow",context:"formatting"});default:return r.day(t,{width:"wide",context:"formatting"})||r.day(t,{width:"abbreviated",context:"formatting"})||r.day(t,{width:"short",context:"formatting"})||r.day(t,{width:"narrow",context:"formatting"})}},validate:function(t,e,r){return e>=0&&e<=6},set:function(t,e,r,n){return(t=Tt(t,r,n)).setUTCHours(0,0,0,0),t},incompatibleTokens:["D","i","e","c","t","T"]},e:{priority:90,parse:function(t,e,r,n){var a=function(t){var e=7*Math.floor((t-1)/7);return(t+n.weekStartsOn+6)%7+e};switch(e){case"e":case"ee":return Zt(e.length,t,a);case"eo":return r.ordinalNumber(t,{unit:"day",valueCallback:a});case"eee":return r.day(t,{width:"abbreviated",context:"formatting"})||r.day(t,{width:"short",context:"formatting"})||r.day(t,{width:"narrow",context:"formatting"});case"eeeee":return r.day(t,{width:"narrow",context:"formatting"});case"eeeeee":return r.day(t,{width:"short",context:"formatting"})||r.day(t,{width:"narrow",context:"formatting"});default:return r.day(t,{width:"wide",context:"formatting"})||r.day(t,{width:"abbreviated",context:"formatting"})||r.day(t,{width:"short",context:"formatting"})||r.day(t,{width:"narrow",context:"formatting"})}},validate:function(t,e,r){return e>=0&&e<=6},set:function(t,e,r,n){return(t=Tt(t,r,n)).setUTCHours(0,0,0,0),t},incompatibleTokens:["y","R","u","q","Q","M","L","I","d","D","E","i","c","t","T"]},c:{priority:90,parse:function(t,e,r,n){var a=function(t){var e=7*Math.floor((t-1)/7);return(t+n.weekStartsOn+6)%7+e};switch(e){case"c":case"cc":return Zt(e.length,t,a);case"co":return r.ordinalNumber(t,{unit:"day",valueCallback:a});case"ccc":return r.day(t,{width:"abbreviated",context:"standalone"})||r.day(t,{width:"short",context:"standalone"})||r.day(t,{width:"narrow",context:"standalone"});case"ccccc":return r.day(t,{width:"narrow",context:"standalone"});case"cccccc":return r.day(t,{width:"short",context:"standalone"})||r.day(t,{width:"narrow",context:"standalone"});default:return r.day(t,{width:"wide",context:"standalone"})||r.day(t,{width:"abbreviated",context:"standalone"})||r.day(t,{width:"short",context:"standalone"})||r.day(t,{width:"narrow",context:"standalone"})}},validate:function(t,e,r){return e>=0&&e<=6},set:function(t,e,r,n){return(t=Tt(t,r,n)).setUTCHours(0,0,0,0),t},incompatibleTokens:["y","R","u","q","Q","M","L","I","d","D","E","i","e","t","T"]},i:{priority:90,parse:function(t,e,r,n){var a=function(t){return 0===t?7:t};switch(e){case"i":case"ii":return Zt(e.length,t);case"io":return r.ordinalNumber(t,{unit:"day"});case"iii":return r.day(t,{width:"abbreviated",context:"formatting",valueCallback:a})||r.day(t,{width:"short",context:"formatting",valueCallback:a})||r.day(t,{width:"narrow",context:"formatting",valueCallback:a});case"iiiii":return r.day(t,{width:"narrow",context:"formatting",valueCallback:a});case"iiiiii":return r.day(t,{width:"short",context:"formatting",valueCallback:a})||r.day(t,{width:"narrow",context:"formatting",valueCallback:a});default:return r.day(t,{width:"wide",context:"formatting",valueCallback:a})||r.day(t,{width:"abbreviated",context:"formatting",valueCallback:a})||r.day(t,{width:"short",context:"formatting",valueCallback:a})||r.day(t,{width:"narrow",context:"formatting",valueCallback:a})}},validate:function(t,e,r){return e>=1&&e<=7},set:function(t,a,i,o){return t=function(t,a){r(2,arguments);var i=e(a);i%7==0&&(i-=7);var o=1,u=n(t),s=u.getUTCDay(),c=((i%7+7)%7<o?7:0)+i-s;return u.setUTCDate(u.getUTCDate()+c),u}(t,i,o),t.setUTCHours(0,0,0,0),t},incompatibleTokens:["y","Y","u","q","Q","M","L","w","d","D","E","e","c","t","T"]},a:{priority:80,parse:function(t,e,r,n){switch(e){case"a":case"aa":case"aaa":return r.dayPeriod(t,{width:"abbreviated",context:"formatting"})||r.dayPeriod(t,{width:"narrow",context:"formatting"});case"aaaaa":return r.dayPeriod(t,{width:"narrow",context:"formatting"});default:return r.dayPeriod(t,{width:"wide",context:"formatting"})||r.dayPeriod(t,{width:"abbreviated",context:"formatting"})||r.dayPeriod(t,{width:"narrow",context:"formatting"})}},set:function(t,e,r,n){return t.setUTCHours($t(r),0,0,0),t},incompatibleTokens:["b","B","H","K","k","t","T"]},b:{priority:80,parse:function(t,e,r,n){switch(e){case"b":case"bb":case"bbb":return r.dayPeriod(t,{width:"abbreviated",context:"formatting"})||r.dayPeriod(t,{width:"narrow",context:"formatting"});case"bbbbb":return r.dayPeriod(t,{width:"narrow",context:"formatting"});default:return r.dayPeriod(t,{width:"wide",context:"formatting"})||r.dayPeriod(t,{width:"abbreviated",context:"formatting"})||r.dayPeriod(t,{width:"narrow",context:"formatting"})}},set:function(t,e,r,n){return t.setUTCHours($t(r),0,0,0),t},incompatibleTokens:["a","B","H","K","k","t","T"]},B:{priority:80,parse:function(t,e,r,n){switch(e){case"B":case"BB":case"BBB":return r.dayPeriod(t,{width:"abbreviated",context:"formatting"})||r.dayPeriod(t,{width:"narrow",context:"formatting"});case"BBBBB":return r.dayPeriod(t,{width:"narrow",context:"formatting"});default:return r.dayPeriod(t,{width:"wide",context:"formatting"})||r.dayPeriod(t,{width:"abbreviated",context:"formatting"})||r.dayPeriod(t,{width:"narrow",context:"formatting"})}},set:function(t,e,r,n){return t.setUTCHours($t(r),0,0,0),t},incompatibleTokens:["a","b","t","T"]},h:{priority:70,parse:function(t,e,r,n){switch(e){case"h":return Bt(Yt,t);case"ho":return r.ordinalNumber(t,{unit:"hour"});default:return Zt(e.length,t)}},validate:function(t,e,r){return e>=1&&e<=12},set:function(t,e,r,n){var a=t.getUTCHours()>=12;return a&&r<12?t.setUTCHours(r+12,0,0,0):a||12!==r?t.setUTCHours(r,0,0,0):t.setUTCHours(0,0,0,0),t},incompatibleTokens:["H","K","k","t","T"]},H:{priority:70,parse:function(t,e,r,n){switch(e){case"H":return Bt(xt,t);case"Ho":return r.ordinalNumber(t,{unit:"hour"});default:return Zt(e.length,t)}},validate:function(t,e,r){return e>=0&&e<=23},set:function(t,e,r,n){return t.setUTCHours(r,0,0,0),t},incompatibleTokens:["a","b","h","K","k","t","T"]},K:{priority:70,parse:function(t,e,r,n){switch(e){case"K":return Bt(Ut,t);case"Ko":return r.ordinalNumber(t,{unit:"hour"});default:return Zt(e.length,t)}},validate:function(t,e,r){return e>=0&&e<=11},set:function(t,e,r,n){return t.getUTCHours()>=12&&r<12?t.setUTCHours(r+12,0,0,0):t.setUTCHours(r,0,0,0),t},incompatibleTokens:["a","b","h","H","k","t","T"]},k:{priority:70,parse:function(t,e,r,n){switch(e){case"k":return Bt(kt,t);case"ko":return r.ordinalNumber(t,{unit:"hour"});default:return Zt(e.length,t)}},validate:function(t,e,r){return e>=1&&e<=24},set:function(t,e,r,n){var a=r<=24?r%24:r;return t.setUTCHours(a,0,0,0),t},incompatibleTokens:["a","b","h","H","K","t","T"]},m:{priority:60,parse:function(t,e,r,n){switch(e){case"m":return Bt(Nt,t);case"mo":return r.ordinalNumber(t,{unit:"minute"});default:return Zt(e.length,t)}},validate:function(t,e,r){return e>=0&&e<=59},set:function(t,e,r,n){return t.setUTCMinutes(r,0,0),t},incompatibleTokens:["t","T"]},s:{priority:50,parse:function(t,e,r,n){switch(e){case"s":return Bt(St,t);case"so":return r.ordinalNumber(t,{unit:"second"});default:return Zt(e.length,t)}},validate:function(t,e,r){return e>=0&&e<=59},set:function(t,e,r,n){return t.setUTCSeconds(r,0),t},incompatibleTokens:["t","T"]},S:{priority:30,parse:function(t,e,r,n){return Zt(e.length,t,(function(t){return Math.floor(t*Math.pow(10,3-e.length))}))},set:function(t,e,r,n){return t.setUTCMilliseconds(r),t},incompatibleTokens:["t","T"]},X:{priority:10,parse:function(t,e,r,n){switch(e){case"X":return zt(Rt,t);case"XX":return zt(It,t);case"XXXX":return zt(Gt,t);case"XXXXX":return zt(jt,t);default:return zt(Xt,t)}},set:function(t,e,r,n){return e.timestampIsSet?t:new Date(t.getTime()-r)},incompatibleTokens:["t","T","x"]},x:{priority:10,parse:function(t,e,r,n){switch(e){case"x":return zt(Rt,t);case"xx":return zt(It,t);case"xxxx":return zt(Gt,t);case"xxxxx":return zt(jt,t);default:return zt(Xt,t)}},set:function(t,e,r,n){return e.timestampIsSet?t:new Date(t.getTime()-r)},incompatibleTokens:["t","T","X"]},t:{priority:40,parse:function(t,e,r,n){return At(t)},set:function(t,e,r,n){return[new Date(1e3*r),{timestampIsSet:!0}]},incompatibleTokens:"*"},T:{priority:20,parse:function(t,e,r,n){return At(t)},set:function(t,e,r,n){return[new Date(r),{timestampIsSet:!0}]},incompatibleTokens:"*"}},re=ee,ne=/[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g,ae=/P+p+|P+|p+|''|'(''|[^'])+('|$)|./g,ie=/^'([^]*?)'?$/,oe=/''/g,ue=/\S/,se=/[a-zA-Z]/;function ce(t,e){if(e.timestampIsSet)return t;var r=new Date(0);return r.setFullYear(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate()),r.setHours(t.getUTCHours(),t.getUTCMinutes(),t.getUTCSeconds(),t.getUTCMilliseconds()),r}function de(t){return t.match(ie)[1].replace(oe,"'")}var le=36e5,fe={dateTimeDelimiter:/[T ]/,timeZoneDelimiter:/[Z ]/i,timezone:/([Z+-].*)$/},he=/^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/,me=/^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/,we=/^([+-])(\d{2})(?::?(\d{2}))?$/;function ge(t){var e,r={},n=t.split(fe.dateTimeDelimiter);if(n.length>2)return r;if(/:/.test(n[0])?(r.date=null,e=n[0]):(r.date=n[0],e=n[1],fe.timeZoneDelimiter.test(r.date)&&(r.date=t.split(fe.timeZoneDelimiter)[0],e=t.substr(r.date.length,t.length))),e){var a=fe.timezone.exec(e);a?(r.time=e.replace(a[1],""),r.timezone=a[1]):r.time=e}return r}function ve(t,e){var r=new RegExp("^(?:(\\d{4}|[+-]\\d{"+(4+e)+"})|(\\d{2}|[+-]\\d{"+(2+e)+"})$)"),n=t.match(r);if(!n)return{year:null};var a=n[1]&&parseInt(n[1]),i=n[2]&&parseInt(n[2]);return{year:null==i?a:100*i,restDateString:t.slice((n[1]||n[2]).length)}}function ye(t,e){if(null===e)return null;var r=t.match(he);if(!r)return null;var n=!!r[4],a=be(r[1]),i=be(r[2])-1,o=be(r[3]),u=be(r[4]),s=be(r[5])-1;if(n)return function(t,e,r){return e>=1&&e<=53&&r>=0&&r<=6}(0,u,s)?function(t,e,r){var n=new Date(0);n.setUTCFullYear(t,0,4);var a=n.getUTCDay()||7,i=7*(e-1)+r+1-a;return n.setUTCDate(n.getUTCDate()+i),n}(e,u,s):new Date(NaN);var c=new Date(0);return function(t,e,r){return e>=0&&e<=11&&r>=1&&r<=(Me[e]||(De(t)?29:28))}(e,i,o)&&function(t,e){return e>=1&&e<=(De(t)?366:365)}(e,a)?(c.setUTCFullYear(e,i,Math.max(a,o)),c):new Date(NaN)}function be(t){return t?parseInt(t):1}function Te(t){var e=t.match(me);if(!e)return null;var r=pe(e[1]),n=pe(e[2]),a=pe(e[3]);return function(t,e,r){if(24===t)return 0===e&&0===r;return r>=0&&r<60&&e>=0&&e<60&&t>=0&&t<25}(r,n,a)?r*le+6e4*n+1e3*a:NaN}function pe(t){return t&&parseFloat(t.replace(",","."))||0}function Ce(t){if("Z"===t)return 0;var e=t.match(we);if(!e)return 0;var r="+"===e[1]?-1:1,n=parseInt(e[2]),a=e[3]&&parseInt(e[3])||0;return function(t,e){return e>=0&&e<=59}(0,a)?r*(n*le+6e4*a):NaN}var Me=[31,null,31,30,31,30,31,31,30,31,30,31];function De(t){return t%400==0||t%4==0&&t%100}const xe={datetime:"MMM d, yyyy, h:mm:ss aaaa",millisecond:"h:mm:ss.SSS aaaa",second:"h:mm:ss aaaa",minute:"h:mm aaaa",hour:"ha",day:"MMM d",week:"PP",month:"MMM yyyy",quarter:"qqq - yyyy",year:"yyyy"};t._adapters._date.override({_id:"date-fns",formats:function(){return xe},parse:function(t,a){if(null==t)return null;const i=typeof t;return"number"===i||t instanceof Date?t=n(t):"string"===i&&(t="string"==typeof a?function(t,a,i,o){r(3,arguments);var u=String(t),s=String(a),d=o||{},l=d.locale||q;if(!l.match)throw new RangeError("locale must contain match property");var f=l.options&&l.options.firstWeekContainsDate,h=null==f?1:e(f),m=null==d.firstWeekContainsDate?h:e(d.firstWeekContainsDate);if(!(m>=1&&m<=7))throw new RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var w=l.options&&l.options.weekStartsOn,g=null==w?0:e(w),v=null==d.weekStartsOn?g:e(d.weekStartsOn);if(!(v>=0&&v<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");if(""===s)return""===u?n(i):new Date(NaN);var y,b={firstWeekContainsDate:m,weekStartsOn:v,locale:l},T=[{priority:10,subPriority:-1,set:ce,index:0}],p=s.match(ae).map((function(t){var e=t[0];return"p"===e||"P"===e?(0,ut[e])(t,l.formatLong,b):t})).join("").match(ne),C=[];for(y=0;y<p.length;y++){var M=p[y];!d.useAdditionalWeekYearTokens&<(M)&&ft(M,s,t),!d.useAdditionalDayOfYearTokens&&dt(M)&&ft(M,s,t);var D=M[0],x=re[D];if(x){var k=x.incompatibleTokens;if(Array.isArray(k)){for(var U=void 0,Y=0;Y<C.length;Y++){var N=C[Y].token;if(-1!==k.indexOf(N)||N===D){U=C[Y];break}}if(U)throw new RangeError("The format string mustn't contain `".concat(U.fullToken,"` and `").concat(M,"` at the same time"))}else if("*"===x.incompatibleTokens&&C.length)throw new RangeError("The format string mustn't contain `".concat(M,"` and any other token at the same time"));C.push({token:D,fullToken:M});var S=x.parse(u,M,l.match,b);if(!S)return new Date(NaN);T.push({priority:x.priority,subPriority:x.subPriority||0,set:x.set,validate:x.validate,value:S.value,index:T.length}),u=S.rest}else{if(D.match(se))throw new RangeError("Format string contains an unescaped latin alphabet character `"+D+"`");if("''"===M?M="'":"'"===D&&(M=de(M)),0!==u.indexOf(M))return new Date(NaN);u=u.slice(M.length)}}if(u.length>0&&ue.test(u))return new Date(NaN);var P=T.map((function(t){return t.priority})).sort((function(t,e){return e-t})).filter((function(t,e,r){return r.indexOf(t)===e})).map((function(t){return T.filter((function(e){return e.priority===t})).sort((function(t,e){return e.subPriority-t.subPriority}))})).map((function(t){return t[0]})),E=n(i);if(isNaN(E))return new Date(NaN);var O=H(E,c(E)),F={};for(y=0;y<P.length;y++){var W=P[y];if(W.validate&&!W.validate(O,W.value,b))return new Date(NaN);var L=W.set(O,F,W.value,b);L[0]?(O=L[0],bt(F,L[1])):O=L}return O}(t,a,new Date,this.options):function(t,n){r(1,arguments);var a=n||{},i=null==a.additionalDigits?2:e(a.additionalDigits);if(2!==i&&1!==i&&0!==i)throw new RangeError("additionalDigits must be 0, 1 or 2");if("string"!=typeof t&&"[object String]"!==Object.prototype.toString.call(t))return new Date(NaN);var o,u=ge(t);if(u.date){var s=ve(u.date,i);o=ye(s.restDateString,s.year)}if(isNaN(o)||!o)return new Date(NaN);var c,d=o.getTime(),l=0;if(u.time&&(l=Te(u.time),isNaN(l)||null===l))return new Date(NaN);if(!u.timezone){var f=new Date(d+l),h=new Date(0);return h.setFullYear(f.getUTCFullYear(),f.getUTCMonth(),f.getUTCDate()),h.setHours(f.getUTCHours(),f.getUTCMinutes(),f.getUTCSeconds(),f.getUTCMilliseconds()),h}return c=Ce(u.timezone),isNaN(c)?new Date(NaN):new Date(d+l+c)}(t,this.options)),m(t)?t.getTime():null},format:function(t,a){return function(t,a,i){r(2,arguments);var o=String(a),u=i||{},s=u.locale||q,d=s.options&&s.options.firstWeekContainsDate,l=null==d?1:e(d),f=null==u.firstWeekContainsDate?l:e(u.firstWeekContainsDate);if(!(f>=1&&f<=7))throw new RangeError("firstWeekContainsDate must be between 1 and 7 inclusively");var h=s.options&&s.options.weekStartsOn,w=null==h?0:e(h),g=null==u.weekStartsOn?w:e(u.weekStartsOn);if(!(g>=0&&g<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");if(!s.localize)throw new RangeError("locale must contain localize property");if(!s.formatLong)throw new RangeError("locale must contain formatLong property");var v=n(t);if(!m(v))throw new RangeError("Invalid time value");var y=c(v),b=H(v,y),T={firstWeekContainsDate:f,weekStartsOn:g,locale:s,_originalDate:v},p=o.match(mt).map((function(t){var e=t[0];return"p"===e||"P"===e?(0,ut[e])(t,s.formatLong,T):t})).join("").match(ht).map((function(e){if("''"===e)return"'";var r=e[0];if("'"===r)return yt(e);var n=nt[r];if(n)return!u.useAdditionalWeekYearTokens&<(e)&&ft(e,a,t),!u.useAdditionalDayOfYearTokens&&dt(e)&&ft(e,a,t),n(b,e,s.localize,T);if(r.match(vt))throw new RangeError("Format string contains an unescaped latin alphabet character `"+r+"`");return e})).join("");return p}(t,a,this.options)},add:function(t,n,s){switch(s){case"millisecond":return o(t,n);case"second":return function(t,n){r(2,arguments);var a=e(n);return o(t,1e3*a)}(t,n);case"minute":return function(t,n){r(2,arguments);var a=e(n);return o(t,6e4*a)}(t,n);case"hour":return function(t,n){r(2,arguments);var a=e(n);return o(t,a*u)}(t,n);case"day":return a(t,n);case"week":return function(t,n){r(2,arguments);var i=e(n),o=7*i;return a(t,o)}(t,n);case"month":return i(t,n);case"quarter":return function(t,n){r(2,arguments);var a=e(n),o=3*a;return i(t,o)}(t,n);case"year":return function(t,n){r(2,arguments);var a=e(n);return i(t,12*a)}(t,n);default:return t}},diff:function(t,e,a){switch(a){case"millisecond":return b(t,e);case"second":return function(t,e){r(2,arguments);var n=b(t,e)/1e3;return n>0?Math.floor(n):Math.ceil(n)}(t,e);case"minute":return function(t,e){r(2,arguments);var n=b(t,e)/6e4;return n>0?Math.floor(n):Math.ceil(n)}(t,e);case"hour":return function(t,e){r(2,arguments);var n=b(t,e)/T;return n>0?Math.floor(n):Math.ceil(n)}(t,e);case"day":return y(t,e);case"week":return function(t,e){r(2,arguments);var n=y(t,e)/7;return n>0?Math.floor(n):Math.ceil(n)}(t,e);case"month":return D(t,e);case"quarter":return function(t,e){r(2,arguments);var n=D(t,e)/3;return n>0?Math.floor(n):Math.ceil(n)}(t,e);case"year":return function(t,e){r(2,arguments);var a=n(t),i=n(e),o=h(a,i),u=Math.abs(g(a,i));a.setFullYear("1584"),i.setFullYear("1584");var s=h(a,i)===-o,c=o*(u-s);return 0===c?0:c}(t,e);default:return 0}},startOf:function(t,e,a){switch(e){case"second":return function(t){r(1,arguments);var e=n(t);return e.setMilliseconds(0),e}(t);case"minute":return function(t){r(1,arguments);var e=n(t);return e.setSeconds(0,0),e}(t);case"hour":return function(t){r(1,arguments);var e=n(t);return e.setMinutes(0,0,0),e}(t);case"day":return d(t);case"week":return s(t);case"isoWeek":return s(t,{weekStartsOn:+a});case"month":return function(t){r(1,arguments);var e=n(t);return e.setDate(1),e.setHours(0,0,0,0),e}(t);case"quarter":return function(t){r(1,arguments);var e=n(t),a=e.getMonth(),i=a-a%3;return e.setMonth(i,1),e.setHours(0,0,0,0),e}(t);case"year":return function(t){r(1,arguments);var e=n(t),a=new Date(0);return a.setFullYear(e.getFullYear(),0,1),a.setHours(0,0,0,0),a}(t);default:return t}},endOf:function(t,a){switch(a){case"second":return function(t){r(1,arguments);var e=n(t);return e.setMilliseconds(999),e}(t);case"minute":return function(t){r(1,arguments);var e=n(t);return e.setSeconds(59,999),e}(t);case"hour":return function(t){r(1,arguments);var e=n(t);return e.setMinutes(59,59,999),e}(t);case"day":return p(t);case"week":return function(t,a){r(1,arguments);var i=a||{},o=i.locale,u=o&&o.options&&o.options.weekStartsOn,s=null==u?0:e(u),c=null==i.weekStartsOn?s:e(i.weekStartsOn);if(!(c>=0&&c<=6))throw new RangeError("weekStartsOn must be between 0 and 6 inclusively");var d=n(t),l=d.getDay(),f=6+(l<c?-7:0)-(l-c);return d.setDate(d.getDate()+f),d.setHours(23,59,59,999),d}(t);case"month":return C(t);case"quarter":return function(t){r(1,arguments);var e=n(t),a=e.getMonth(),i=a-a%3+3;return e.setMonth(i,0),e.setHours(23,59,59,999),e}(t);case"year":return function(t){r(1,arguments);var e=n(t),a=e.getFullYear();return e.setFullYear(a+1,0,0),e.setHours(23,59,59,999),e}(t);default:return t}}})}));
|
@@ -4,14 +4,6 @@ class JobMetricsOverviewChart extends BaseChart {
|
|
4
4
|
this.swatches = [];
|
5
5
|
this.visibleKls = options.visibleKls;
|
6
6
|
|
7
|
-
const countBuckets = this.options.labels.length / 60;
|
8
|
-
this.labelBuckets = this.options.labels.reduce((acc, label, index) => {
|
9
|
-
const bucket = Math.floor(index / countBuckets);
|
10
|
-
acc[bucket] = acc[bucket] || [];
|
11
|
-
acc[bucket].push(label);
|
12
|
-
return acc;
|
13
|
-
}, []);
|
14
|
-
|
15
7
|
this.init();
|
16
8
|
}
|
17
9
|
|
@@ -60,7 +52,7 @@ class JobMetricsOverviewChart extends BaseChart {
|
|
60
52
|
|
61
53
|
return {
|
62
54
|
label: kls,
|
63
|
-
data: this.
|
55
|
+
data: this.dataFromSeries(this.options.series[kls]),
|
64
56
|
borderColor: color,
|
65
57
|
backgroundColor: color,
|
66
58
|
borderWidth: 2,
|
@@ -68,24 +60,9 @@ class JobMetricsOverviewChart extends BaseChart {
|
|
68
60
|
};
|
69
61
|
}
|
70
62
|
|
71
|
-
|
72
|
-
// `
|
73
|
-
|
74
|
-
return this.labelBuckets.reduce((acc, labels) => {
|
75
|
-
const bucketValues = labels.map(label => series[label]).filter(v => v);
|
76
|
-
if (bucketValues.length > 0) {
|
77
|
-
// Sum up the values for each bucket that has data.
|
78
|
-
// The new label is the bucket's first label, its start time.
|
79
|
-
acc[labels[0]] = bucketValues.reduce((a, b) => a + b, 0);
|
80
|
-
}
|
81
|
-
return acc;
|
82
|
-
}, {});
|
83
|
-
}
|
84
|
-
|
85
|
-
buildTooltipTitle(items) {
|
86
|
-
const [first, ...rest] = this.labelBuckets.find((labels) => labels[0] === items[0].label);
|
87
|
-
const title = [first, rest[rest.length - 1]].filter(v => v).join(" - ");
|
88
|
-
return `${title} UTC`
|
63
|
+
dataFromSeries(series) {
|
64
|
+
// Chart.js expects `data` to be an array of objects with `x` and `y` values.
|
65
|
+
return Object.entries(series).map(([isoTime, val]) => ({ x: isoTime, y: val }));
|
89
66
|
}
|
90
67
|
|
91
68
|
get chartOptions() {
|
@@ -94,6 +71,12 @@ class JobMetricsOverviewChart extends BaseChart {
|
|
94
71
|
aspectRatio: 4,
|
95
72
|
scales: {
|
96
73
|
...super.chartOptions.scales,
|
74
|
+
x: {
|
75
|
+
...super.chartOptions.scales.x,
|
76
|
+
type: "time",
|
77
|
+
min: this.options.starts_at,
|
78
|
+
max: this.options.ends_at,
|
79
|
+
},
|
97
80
|
y: {
|
98
81
|
...super.chartOptions.scales.y,
|
99
82
|
beginAtZero: true,
|
@@ -108,12 +91,11 @@ class JobMetricsOverviewChart extends BaseChart {
|
|
108
91
|
tooltip: {
|
109
92
|
...super.chartOptions.plugins.tooltip,
|
110
93
|
callbacks: {
|
111
|
-
title: (items) => this.buildTooltipTitle(items),
|
112
94
|
label: (item) =>
|
113
95
|
`${item.dataset.label}: ${item.parsed.y.toFixed(1)} ` +
|
114
96
|
`${this.options.units}`,
|
115
97
|
footer: (items) => {
|
116
|
-
const bucket = items[0].
|
98
|
+
const bucket = items[0].raw.x;
|
117
99
|
const marks = this.options.marks.filter(([b, _]) => b == bucket);
|
118
100
|
return marks.map(
|
119
101
|
([b, msg]) => `${this.options.markLabel}: ${msg}`
|
@@ -206,7 +188,7 @@ class HistBubbleChart extends BaseChart {
|
|
206
188
|
});
|
207
189
|
|
208
190
|
// Chart.js will not calculate the bubble size. We have to do that.
|
209
|
-
const maxRadius = this.el.offsetWidth /
|
191
|
+
const maxRadius = this.el.offsetWidth / 100;
|
210
192
|
const minRadius = 1;
|
211
193
|
const multiplier = (maxRadius / maxCount) * 1.5;
|
212
194
|
data.forEach((entry) => {
|
@@ -230,8 +212,9 @@ class HistBubbleChart extends BaseChart {
|
|
230
212
|
...super.chartOptions.scales,
|
231
213
|
x: {
|
232
214
|
...super.chartOptions.scales.x,
|
233
|
-
type: "
|
234
|
-
|
215
|
+
type: "time",
|
216
|
+
min: this.options.starts_at,
|
217
|
+
max: this.options.ends_at,
|
235
218
|
},
|
236
219
|
y: {
|
237
220
|
...super.chartOptions.scales.y,
|
@@ -246,7 +229,6 @@ class HistBubbleChart extends BaseChart {
|
|
246
229
|
tooltip: {
|
247
230
|
...super.chartOptions.plugins.tooltip,
|
248
231
|
callbacks: {
|
249
|
-
title: (items) => `${items[0].raw.x} UTC`,
|
250
232
|
label: (item) =>
|
251
233
|
`${item.parsed.y} ${this.options.yUnits}: ${item.raw.count} ${this.options.zUnits}`,
|
252
234
|
footer: (items) => {
|
@@ -557,7 +557,7 @@ body > footer .nav {
|
|
557
557
|
@media (prefers-color-scheme: dark) {
|
558
558
|
:root {
|
559
559
|
/* --color-primary: oklch(65% 0.15 13); */
|
560
|
-
--color-primary: oklch(
|
560
|
+
--color-primary: oklch(65% 0.22 13);
|
561
561
|
--color-bg: oklch(22% 0.01 256);
|
562
562
|
--color-elevated: oklch(19% 0.01 256);
|
563
563
|
--color-border: oklch(25% 0.01 256);
|
data/web/views/_job_info.erb
CHANGED
@@ -68,12 +68,12 @@
|
|
68
68
|
</tr>
|
69
69
|
<tr>
|
70
70
|
<th><%= t('LastRetry') %></th>
|
71
|
-
<td><%= relative_time(
|
71
|
+
<td><%= relative_time(job.retried_at) %></td>
|
72
72
|
</tr>
|
73
73
|
<% else %>
|
74
74
|
<tr>
|
75
75
|
<th><%= t('OriginallyFailed') %></th>
|
76
|
-
<td><%= relative_time(
|
76
|
+
<td><%= relative_time(job.failed_at) %></td>
|
77
77
|
</tr>
|
78
78
|
<% end %>
|
79
79
|
<tr>
|
@@ -1,12 +1,15 @@
|
|
1
1
|
<div class="filter">
|
2
|
-
<
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
<form id="metrics-form" class="form-inline" action="<%= path %>" method="get">
|
3
|
+
<label for="substr"><%= t('Filter') %></label>
|
4
|
+
<input id="class-filter" class="form-control" type="text" name="substr" placeholder="<%= t('Name') %>" value="<%= h url_params("substr") %>">
|
5
|
+
<select id="period-selector" class="form-control" name="period">
|
6
|
+
<% periods.each_key do |code| %>
|
7
|
+
<% if code == period %>
|
8
|
+
<option selected value="<%= code %>"><%= code %></option>
|
9
|
+
<% else %>
|
10
|
+
<option value="<%= code %>"><%= code %></option>
|
11
|
+
<% end %>
|
9
12
|
<% end %>
|
10
|
-
|
11
|
-
</
|
13
|
+
</select>
|
14
|
+
</form>
|
12
15
|
</div>
|
data/web/views/_nav.erb
CHANGED
data/web/views/dashboard.erb
CHANGED
@@ -99,5 +99,6 @@
|
|
99
99
|
|
100
100
|
<script type="text/javascript" src="<%= root_path %>javascripts/chart.min.js" nonce="<%= csp_nonce %>"></script>
|
101
101
|
<script type="text/javascript" src="<%= root_path %>javascripts/chartjs-plugin-annotation.min.js" nonce="<%= csp_nonce %>"></script>
|
102
|
+
<script type="text/javascript" src="<%= root_path %>javascripts/chartjs-adapter-date-fns.min.js" nonce="<%= csp_nonce %>"></script>
|
102
103
|
<script type="text/javascript" src="<%= root_path %>javascripts/base-charts.js" nonce="<%= csp_nonce %>"></script>
|
103
104
|
<script type="text/javascript" src="<%= root_path %>javascripts/dashboard-charts.js" nonce="<%= csp_nonce %>"></script>
|
data/web/views/layout.erb
CHANGED
data/web/views/metrics.erb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
<%= script_tag "javascripts/chart.min.js" %>
|
2
|
+
<%= script_tag "javascripts/chartjs-plugin-annotation.min.js" %>
|
3
|
+
<%= script_tag "javascripts/chartjs-adapter-date-fns.min.js" %>
|
4
|
+
<%= script_tag "javascripts/base-charts.js" %>
|
4
5
|
|
5
6
|
<section>
|
6
7
|
<header>
|
@@ -8,22 +9,8 @@
|
|
8
9
|
<%= t('Metrics') %>
|
9
10
|
<a target="blank" href="https://github.com/sidekiq/sidekiq/wiki/Metrics"><span class="info-circle" title="Click to learn more about metrics">?</span></a>
|
10
11
|
</h1>
|
11
|
-
|
12
|
-
|
13
|
-
<form id="metrics-form" class="form-inline" action="<%= root_path %>metrics" method="get">
|
14
|
-
<label for="substr"><%= t('Filter') %></label>
|
15
|
-
<input id="class-filter" class="form-control" type="text" name="substr" placeholder="<%= t('Name') %>" value="<%= h url_params("substr") %>">
|
16
|
-
<select id="period-selector" class="form-control" name="period">
|
17
|
-
<% @periods.each_key do |code| %>
|
18
|
-
<% if code == @period %>
|
19
|
-
<option selected value="<%= code %>"><%= code %></option>
|
20
|
-
<% else %>
|
21
|
-
<option value="<%= code %>"><%= code %></option>
|
22
|
-
<% end %>
|
23
|
-
<% end %>
|
24
|
-
</select>
|
25
|
-
</form>
|
26
|
-
</div>
|
12
|
+
|
13
|
+
<%= erb :_metrics_period_select, locals: { periods: @periods, period: @period, path: "#{root_path}metrics" } %>
|
27
14
|
</header>
|
28
15
|
|
29
16
|
<%
|
@@ -38,7 +25,8 @@
|
|
38
25
|
<%= to_json({
|
39
26
|
series: job_results.map { |(kls, jr)| [kls, jr.dig("series", "s")] }.to_h,
|
40
27
|
marks: @query_result.marks.map { |m| [m.bucket, m.label] },
|
41
|
-
|
28
|
+
starts_at: @query_result.starts_at.iso8601,
|
29
|
+
ends_at: @query_result.ends_at.iso8601,
|
42
30
|
visibleKls: visible_kls,
|
43
31
|
yLabel: t('TotalExecutionTime'),
|
44
32
|
units: t('Seconds').downcase,
|
@@ -88,6 +76,9 @@
|
|
88
76
|
</table>
|
89
77
|
</div>
|
90
78
|
|
91
|
-
|
79
|
+
<% if job_results.any? %>
|
80
|
+
<p><small>Data from <%= @query_result.starts_at %> to <%= @query_result.ends_at %>.<% if @period == "1h" %> Auto-refreshing every 60 seconds.<% end %></small></p>
|
81
|
+
<% end %>
|
82
|
+
|
92
83
|
</section>
|
93
|
-
|
84
|
+
<%= script_tag "javascripts/metrics.js" %>
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
<%= script_tag "javascripts/chart.min.js" %>
|
2
|
+
<%= script_tag "javascripts/chartjs-plugin-annotation.min.js" %>
|
3
|
+
<%= script_tag "javascripts/chartjs-adapter-date-fns.min.js" %>
|
4
|
+
<%= script_tag "javascripts/base-charts.js" %>
|
4
5
|
|
5
6
|
<%
|
6
7
|
job_result = @query_result.job_results[@name]
|
@@ -33,7 +34,8 @@
|
|
33
34
|
<%= to_json({
|
34
35
|
hist: job_result.hist,
|
35
36
|
marks: @query_result.marks.map { |m| [m.bucket, m.label] },
|
36
|
-
|
37
|
+
starts_at: @query_result.starts_at.iso8601,
|
38
|
+
ends_at: @query_result.ends_at.iso8601,
|
37
39
|
histIntervals: bucket_intervals,
|
38
40
|
yLabel: t('ExecutionTime'),
|
39
41
|
markLabel: t('Deploy'),
|
@@ -53,4 +55,4 @@
|
|
53
55
|
<div class="alert alert-success"><%= t('NoJobMetricsFound') %></div>
|
54
56
|
<% end %>
|
55
57
|
</section>
|
56
|
-
|
58
|
+
<%= script_tag "javascripts/metrics.js" %>
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 8.0.0.
|
4
|
+
version: 8.0.0.beta2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Perham
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-02-
|
10
|
+
date: 2025-02-26 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: redis-client
|
@@ -176,6 +176,7 @@ files:
|
|
176
176
|
- web/assets/javascripts/application.js
|
177
177
|
- web/assets/javascripts/base-charts.js
|
178
178
|
- web/assets/javascripts/chart.min.js
|
179
|
+
- web/assets/javascripts/chartjs-adapter-date-fns.min.js
|
179
180
|
- web/assets/javascripts/chartjs-plugin-annotation.min.js
|
180
181
|
- web/assets/javascripts/dashboard-charts.js
|
181
182
|
- web/assets/javascripts/dashboard.js
|