async-background 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +67 -0
- data/README.md +36 -15
- data/async-background.gemspec +13 -7
- data/lib/async/background/queue/schema.rb +14 -14
- data/lib/async/background/queue/socket_waker.rb +115 -52
- data/lib/async/background/queue/store.rb +21 -38
- data/lib/async/background/runner/queue_execution.rb +32 -8
- data/lib/async/background/runner/schedule.rb +16 -13
- data/lib/async/background/runner.rb +128 -38
- data/lib/async/background/runtime/notification.rb +41 -0
- data/lib/async/background/runtime/semaphore.rb +147 -0
- data/lib/async/background/runtime/task.rb +145 -0
- data/lib/async/background/runtime/task_group.rb +81 -0
- data/lib/async/background/runtime.rb +243 -0
- data/lib/async/background/scheduler.rb +145 -0
- data/lib/async/background/version.rb +1 -1
- data/lib/async/background/web/app.rb +22 -26
- data/lib/async/background/web/configuration.rb +40 -93
- data/lib/async/background/web/cursor.rb +10 -21
- data/lib/async/background/web/event_hub.rb +12 -7
- data/lib/async/background/web/metrics_reader.rb +29 -35
- data/lib/async/background/web/response.rb +39 -51
- data/lib/async/background/web/serializer.rb +23 -63
- data/lib/async/background/web/snapshot.rb +32 -78
- data/lib/async/background/web/sql.rb +58 -64
- data/lib/async/background.rb +1 -2
- metadata +26 -22
|
@@ -9,79 +9,73 @@ module Async
|
|
|
9
9
|
ROLLBACK = 'ROLLBACK'.freeze
|
|
10
10
|
QUERY_ONLY = 'PRAGMA query_only = ON'.freeze
|
|
11
11
|
BUSY_TIMEOUT = 'PRAGMA busy_timeout = 2000'.freeze
|
|
12
|
+
BASE_COLUMNS = %w[id class_name args options].freeze
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
STATUS_PREDICATE = {
|
|
15
|
+
executing: "status = 'running' AND started_at IS NOT NULL",
|
|
16
|
+
claimed: "status = 'running' AND started_at IS NULL",
|
|
17
|
+
pending: "status = 'pending'",
|
|
18
|
+
done: "status = 'done'",
|
|
19
|
+
failed: "status = 'failed'"
|
|
20
|
+
}.freeze
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
EXTRA_COLUMNS = {
|
|
23
|
+
executing: %w[started_at locked_by locked_at],
|
|
24
|
+
claimed: %w[locked_at locked_by],
|
|
25
|
+
pending: %w[created_at run_at],
|
|
26
|
+
done: %w[finished_at duration_ms],
|
|
27
|
+
failed: %w[finished_at duration_ms last_error_class last_error_message]
|
|
28
|
+
}.freeze
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
KEYSET = {
|
|
31
|
+
executing: ['started_at', :asc],
|
|
32
|
+
claimed: ['locked_at', :asc],
|
|
33
|
+
pending: ['run_at', :asc],
|
|
34
|
+
done: ['finished_at', :desc],
|
|
35
|
+
failed: ['finished_at', :desc]
|
|
36
|
+
}.freeze
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
FROM jobs
|
|
39
|
-
WHERE status = 'done'
|
|
40
|
-
ORDER BY finished_at DESC, id DESC
|
|
41
|
-
LIMIT ?
|
|
42
|
-
SQL
|
|
38
|
+
ORDER_SQL = {asc: 'ORDER BY %<column>s, id', desc: 'ORDER BY %<column>s DESC, id DESC'}.freeze
|
|
39
|
+
SEEK_SQL = {asc: '(%<column>s, id) > (?, ?)', desc: '(%<column>s, id) < (?, ?)'}.freeze
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
WHERE status = 'done' AND (finished_at, id) < (?, ?)
|
|
48
|
-
ORDER BY finished_at DESC, id DESC
|
|
49
|
-
LIMIT ?
|
|
50
|
-
SQL
|
|
41
|
+
def self.columns_for(status)
|
|
42
|
+
(BASE_COLUMNS + EXTRA_COLUMNS.fetch(status)).join(', ')
|
|
43
|
+
end
|
|
51
44
|
|
|
52
|
-
|
|
53
|
-
SELECT
|
|
54
|
-
|
|
55
|
-
FROM jobs
|
|
56
|
-
WHERE status = 'failed'
|
|
57
|
-
ORDER BY finished_at DESC, id DESC
|
|
58
|
-
LIMIT ?
|
|
59
|
-
SQL
|
|
45
|
+
def self.count_query(status)
|
|
46
|
+
"SELECT COUNT(*) FROM jobs WHERE #{STATUS_PREDICATE.fetch(status)}".freeze
|
|
47
|
+
end
|
|
60
48
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
WHERE status = 'failed' AND (finished_at, id) < (?, ?)
|
|
66
|
-
ORDER BY finished_at DESC, id DESC
|
|
67
|
-
LIMIT ?
|
|
68
|
-
SQL
|
|
49
|
+
def self.list_query(status, seek: false)
|
|
50
|
+
column, direction = KEYSET.fetch(status)
|
|
51
|
+
predicate = STATUS_PREDICATE.fetch(status)
|
|
52
|
+
predicate += " AND #{format(SEEK_SQL.fetch(direction), column: column)}" if seek
|
|
69
53
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
54
|
+
<<~SQL.freeze
|
|
55
|
+
SELECT #{columns_for(status)}
|
|
56
|
+
FROM jobs
|
|
57
|
+
WHERE #{predicate}
|
|
58
|
+
#{format(ORDER_SQL.fetch(direction), column: column)}
|
|
59
|
+
LIMIT ?
|
|
60
|
+
SQL
|
|
61
|
+
end
|
|
77
62
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
63
|
+
OVERVIEW_EXECUTING = count_query(:executing)
|
|
64
|
+
OVERVIEW_CLAIMED = count_query(:claimed)
|
|
65
|
+
OVERVIEW_PENDING = count_query(:pending)
|
|
66
|
+
OVERVIEW_DONE = count_query(:done)
|
|
67
|
+
OVERVIEW_FAILED = count_query(:failed)
|
|
68
|
+
OVERVIEW_NEXT_PENDING = "SELECT MIN(run_at) FROM jobs WHERE #{STATUS_PREDICATE.fetch(:pending)}".freeze
|
|
69
|
+
|
|
70
|
+
EXECUTING = list_query(:executing)
|
|
71
|
+
CLAIMED = list_query(:claimed)
|
|
72
|
+
DONE = list_query(:done)
|
|
73
|
+
FAILED = list_query(:failed)
|
|
74
|
+
PENDING = list_query(:pending)
|
|
75
|
+
|
|
76
|
+
DONE_AFTER = list_query(:done, seek: true)
|
|
77
|
+
FAILED_AFTER = list_query(:failed, seek: true)
|
|
78
|
+
PENDING_AFTER = list_query(:pending, seek: true)
|
|
85
79
|
end
|
|
86
80
|
end
|
|
87
81
|
end
|
data/lib/async/background.rb
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'async'
|
|
4
|
-
require 'async/semaphore'
|
|
5
3
|
require 'console'
|
|
6
4
|
require 'fugit'
|
|
7
5
|
require 'tmpdir'
|
|
8
6
|
|
|
9
7
|
require_relative 'background/version'
|
|
8
|
+
require_relative 'background/runtime'
|
|
10
9
|
require_relative 'background/clock'
|
|
11
10
|
require_relative 'background/min_heap'
|
|
12
11
|
require_relative 'background/entry'
|
metadata
CHANGED
|
@@ -1,31 +1,30 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: async-background
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Roman Hajdarov
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
13
|
+
name: console
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
16
|
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '1.0'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - "~>"
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '1.0'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
27
|
+
name: fugit
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
30
29
|
requirements:
|
|
31
30
|
- - "~>"
|
|
@@ -39,33 +38,33 @@ dependencies:
|
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
39
|
version: '1.0'
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
41
|
+
name: base64
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
44
43
|
requirements:
|
|
45
44
|
- - "~>"
|
|
46
45
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
46
|
+
version: '0.2'
|
|
48
47
|
type: :runtime
|
|
49
48
|
prerelease: false
|
|
50
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
50
|
requirements:
|
|
52
51
|
- - "~>"
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
53
|
+
version: '0.2'
|
|
55
54
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
55
|
+
name: async
|
|
57
56
|
requirement: !ruby/object:Gem::Requirement
|
|
58
57
|
requirements:
|
|
59
58
|
- - "~>"
|
|
60
59
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0
|
|
62
|
-
type: :
|
|
60
|
+
version: '2.0'
|
|
61
|
+
type: :development
|
|
63
62
|
prerelease: false
|
|
64
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
64
|
requirements:
|
|
66
65
|
- - "~>"
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0
|
|
67
|
+
version: '2.0'
|
|
69
68
|
- !ruby/object:Gem::Dependency
|
|
70
69
|
name: rake
|
|
71
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -128,10 +127,11 @@ dependencies:
|
|
|
128
127
|
- - "<"
|
|
129
128
|
- !ruby/object:Gem::Version
|
|
130
129
|
version: '0.5'
|
|
131
|
-
description: A production-grade lightweight scheduler built on
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
130
|
+
description: 'A production-grade lightweight background job scheduler built on the
|
|
131
|
+
Fiber::Scheduler interface itself, not on any one implementation: it runs under
|
|
132
|
+
Async/Falcon, Itsi, or anything else that installs a scheduler. Single event loop
|
|
133
|
+
with min-heap timer, skip-overlapping execution, jitter, monotonic clock intervals,
|
|
134
|
+
semaphore concurrency control, and deterministic worker sharding.'
|
|
135
135
|
email:
|
|
136
136
|
- romnhajdarov@gmail.com
|
|
137
137
|
executables: []
|
|
@@ -159,6 +159,12 @@ files:
|
|
|
159
159
|
- lib/async/background/runner.rb
|
|
160
160
|
- lib/async/background/runner/queue_execution.rb
|
|
161
161
|
- lib/async/background/runner/schedule.rb
|
|
162
|
+
- lib/async/background/runtime.rb
|
|
163
|
+
- lib/async/background/runtime/notification.rb
|
|
164
|
+
- lib/async/background/runtime/semaphore.rb
|
|
165
|
+
- lib/async/background/runtime/task.rb
|
|
166
|
+
- lib/async/background/runtime/task_group.rb
|
|
167
|
+
- lib/async/background/scheduler.rb
|
|
162
168
|
- lib/async/background/version.rb
|
|
163
169
|
- lib/async/background/web.rb
|
|
164
170
|
- lib/async/background/web/app.rb
|
|
@@ -183,7 +189,6 @@ metadata:
|
|
|
183
189
|
source_code_uri: https://github.com/roman-haidarov/async-background
|
|
184
190
|
changelog_uri: https://github.com/roman-haidarov/async-background/blob/main/CHANGELOG.md
|
|
185
191
|
bug_tracker_uri: https://github.com/roman-haidarov/async-background/issues
|
|
186
|
-
post_install_message:
|
|
187
192
|
rdoc_options: []
|
|
188
193
|
require_paths:
|
|
189
194
|
- lib
|
|
@@ -198,8 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
198
203
|
- !ruby/object:Gem::Version
|
|
199
204
|
version: '0'
|
|
200
205
|
requirements: []
|
|
201
|
-
rubygems_version: 3.
|
|
202
|
-
signing_key:
|
|
206
|
+
rubygems_version: 3.6.7
|
|
203
207
|
specification_version: 4
|
|
204
|
-
summary: Lightweight heap-based cron/interval scheduler for
|
|
208
|
+
summary: Lightweight heap-based cron/interval scheduler for any Fiber scheduler.
|
|
205
209
|
test_files: []
|