cosmonats 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +208 -156
  3. data/lib/cosmo/active_job/adapter.rb +46 -0
  4. data/lib/cosmo/active_job/executor.rb +16 -0
  5. data/lib/cosmo/active_job/options.rb +50 -0
  6. data/lib/cosmo/active_job.rb +29 -0
  7. data/lib/cosmo/api/busy.rb +2 -2
  8. data/lib/cosmo/api/counter.rb +2 -2
  9. data/lib/cosmo/api/cron/entry.rb +99 -0
  10. data/lib/cosmo/api/cron.rb +118 -0
  11. data/lib/cosmo/api/kv.rb +35 -13
  12. data/lib/cosmo/api/stream.rb +43 -8
  13. data/lib/cosmo/api.rb +1 -0
  14. data/lib/cosmo/cli.rb +27 -10
  15. data/lib/cosmo/client.rb +52 -4
  16. data/lib/cosmo/config.rb +9 -0
  17. data/lib/cosmo/job/data.rb +1 -1
  18. data/lib/cosmo/job/limit.rb +51 -0
  19. data/lib/cosmo/job/processor.rb +63 -7
  20. data/lib/cosmo/job.rb +51 -2
  21. data/lib/cosmo/processor.rb +1 -1
  22. data/lib/cosmo/railtie.rb +21 -0
  23. data/lib/cosmo/sentry/auto.rb +6 -0
  24. data/lib/cosmo/sentry/job_processor_middleware.rb +66 -0
  25. data/lib/cosmo/stream/processor.rb +2 -2
  26. data/lib/cosmo/stream.rb +2 -1
  27. data/lib/cosmo/utils/hash.rb +13 -0
  28. data/lib/cosmo/utils/overrides.rb +1 -1
  29. data/lib/cosmo/version.rb +1 -1
  30. data/lib/cosmo/web/assets/app.css +59 -0
  31. data/lib/cosmo/web/controllers/crons.rb +41 -0
  32. data/lib/cosmo/web/controllers/jobs.rb +7 -3
  33. data/lib/cosmo/web/controllers/streams.rb +1 -1
  34. data/lib/cosmo/web/helpers/application.rb +4 -0
  35. data/lib/cosmo/web/views/actions/index.erb +1 -1
  36. data/lib/cosmo/web/views/crons/_table.erb +58 -0
  37. data/lib/cosmo/web/views/crons/index.erb +10 -0
  38. data/lib/cosmo/web/views/jobs/_busy.erb +54 -49
  39. data/lib/cosmo/web/views/jobs/_dead.erb +70 -65
  40. data/lib/cosmo/web/views/jobs/_enqueued.erb +85 -56
  41. data/lib/cosmo/web/views/jobs/_scheduled.erb +53 -48
  42. data/lib/cosmo/web/views/jobs/_stats.erb +5 -1
  43. data/lib/cosmo/web/views/jobs/_tabs.erb +6 -0
  44. data/lib/cosmo/web/views/jobs/busy.erb +8 -6
  45. data/lib/cosmo/web/views/jobs/dead.erb +6 -5
  46. data/lib/cosmo/web/views/jobs/enqueued.erb +8 -6
  47. data/lib/cosmo/web/views/jobs/index.erb +1 -1
  48. data/lib/cosmo/web/views/jobs/scheduled.erb +6 -5
  49. data/lib/cosmo/web/views/layout.erb +2 -1
  50. data/lib/cosmo/web.rb +5 -0
  51. data/lib/cosmo.rb +1 -0
  52. data/sig/cosmo/active_job/adapter.rbs +13 -0
  53. data/sig/cosmo/active_job/executor.rbs +9 -0
  54. data/sig/cosmo/active_job/options.rbs +14 -0
  55. data/sig/cosmo/api/cron/entry.rbs +30 -0
  56. data/sig/cosmo/api/cron.rbs +25 -0
  57. data/sig/cosmo/api/kv.rbs +4 -6
  58. data/sig/cosmo/api/stream.rbs +6 -0
  59. data/sig/cosmo/client.rbs +9 -1
  60. data/sig/cosmo/job/data.rbs +1 -1
  61. data/sig/cosmo/job/limit.rbs +18 -0
  62. data/sig/cosmo/job/processor.rbs +3 -1
  63. data/sig/cosmo/job.rbs +9 -4
  64. data/sig/cosmo/railtie.rbs +4 -0
  65. data/sig/cosmo/utils/hash.rbs +4 -0
  66. metadata +23 -2
@@ -1,5 +1,5 @@
1
1
  <section>
2
- <header></header>
2
+ <header><%= render('jobs/_tabs') %></header>
3
3
 
4
4
  <div hx-get="<%= url_for('/jobs/_stats') %>"
5
5
  hx-trigger="load, every 5s"
@@ -7,10 +7,12 @@
7
7
  <div class="alert alert-info">Loading statistics…</div>
8
8
  </div>
9
9
 
10
- <div id="content"
11
- hx-get="<%= url_for('/jobs/_enqueued', stream_name: @stream_name) %>"
12
- hx-trigger="load"
13
- hx-swap="innerHTML">
14
- <div class="alert alert-info">Loading enqueued jobs&hellip;</div>
10
+ <div id="content">
11
+ <div id="enqueued-poller"
12
+ hx-get="<%= url_for('/jobs/_enqueued', stream_name: @stream_name) %>"
13
+ hx-trigger="load"
14
+ hx-swap="outerHTML">
15
+ <div class="alert alert-info">Loading enqueued jobs&hellip;</div>
16
+ </div>
15
17
  </div>
16
18
  </section>
@@ -1,5 +1,5 @@
1
1
  <section>
2
- <header></header>
2
+ <header><%= render('jobs/_tabs') %></header>
3
3
 
4
4
  <div hx-get="<%= url_for('/jobs/_stats') %>"
5
5
  hx-trigger="load, every 5s"
@@ -1,5 +1,5 @@
1
1
  <section>
2
- <header></header>
2
+ <header><%= render('jobs/_tabs') %></header>
3
3
 
4
4
  <div hx-get="<%= url_for('/jobs/_stats') %>"
5
5
  hx-trigger="load, every 5s"
@@ -8,10 +8,11 @@
8
8
  </div>
9
9
 
10
10
  <div id="content">
11
- <div hx-get="<%= url_for('/jobs/_scheduled') %>"
12
- hx-trigger="load, every 5s"
13
- hx-swap="innerHTML">
14
- <div class="alert alert-info">Loading scheduled jobs…</div>
11
+ <div id="scheduled-poller"
12
+ hx-get="<%= url_for('/jobs/_scheduled') %>"
13
+ hx-trigger="load"
14
+ hx-swap="outerHTML">
15
+ <div class="alert alert-info">Loading scheduled jobs&hellip;</div>
15
16
  </div>
16
17
  </div>
17
18
  </section>
@@ -14,7 +14,7 @@
14
14
  <a href="<%= url_for('/jobs') %>" class="navbar-brand">🚀 Cosmo</a>
15
15
  <ul class="nav-list">
16
16
  <li>
17
- <a href="<%= url_for('/jobs') %>" class="<%= "active" if current_page?('/jobs') %>">Jobs</a>
17
+ <a href="<%= url_for('/jobs') %>" class="<%= "active" if path_prefix?('/jobs', '/crons') %>">Jobs</a>
18
18
  </li>
19
19
  <li>
20
20
  <a href="<%= url_for('/streams') %>" class="<%= "active" if current_page?('/streams') %>">Streams</a>
@@ -28,6 +28,7 @@
28
28
  </header>
29
29
  <main class="container">
30
30
  <%= content_for :view %>
31
+ <div id="global-spinner" class="htmx-indicator" aria-hidden="true"></div>
31
32
  </main>
32
33
  </body>
33
34
  </html>
data/lib/cosmo/web.rb CHANGED
@@ -9,6 +9,7 @@ require "cosmo/web/controllers/application"
9
9
  require "cosmo/web/controllers/jobs"
10
10
  require "cosmo/web/controllers/streams"
11
11
  require "cosmo/web/controllers/actions"
12
+ require "cosmo/web/controllers/crons"
12
13
 
13
14
  module Cosmo
14
15
  class Web
@@ -43,6 +44,10 @@ module Cosmo
43
44
  in [:get, "/streams/_info"] then [Controllers::Streams, :_info]
44
45
  in [:patch, "/streams/pause"] then [Controllers::Streams, :pause]
45
46
  in [:patch, "/streams/unpause"] then [Controllers::Streams, :unpause]
47
+ in [:get, "/crons"] then [Controllers::Crons, :index]
48
+ in [:get, "/crons/_table"] then [Controllers::Crons, :_table]
49
+ in [:delete, "/crons/delete"] then [Controllers::Crons, :delete]
50
+ in [:post, "/crons/run"] then [Controllers::Crons, :run_now]
46
51
  in [:get, "/actions"] then [Controllers::Actions, :index]
47
52
  in [:get, "/assets/htmx.min.js.gz"] then serve("htmx.2.0.8.min.js.gz",
48
53
  "application/javascript",
data/lib/cosmo.rb CHANGED
@@ -12,6 +12,7 @@ require "cosmo/stream"
12
12
  require "cosmo/cli"
13
13
  require "cosmo/engine"
14
14
  require "cosmo/api"
15
+ require "cosmo/railtie" if defined?(Rails::Railtie)
15
16
 
16
17
  module Cosmo
17
18
  class Error < StandardError; end
@@ -0,0 +1,13 @@
1
+ module Cosmo
2
+ module ActiveJobAdapter
3
+ class Adapter
4
+ def enqueue: (untyped job) -> String
5
+ def enqueue_at: (untyped job, Numeric timestamp) -> String
6
+
7
+ private
8
+
9
+ def publish: (untyped job, Numeric? timestamp) -> String
10
+ def job_cosmo_options: (untyped job) -> Hash[Symbol, untyped]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Cosmo
2
+ module ActiveJobAdapter
3
+ class Executor
4
+ include Cosmo::Job
5
+
6
+ def perform: (Hash[Symbol, untyped] job_data) -> void
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ module Cosmo
2
+ module ActiveJobAdapter
3
+ VALID_OPTIONS: ::Array[::Symbol]
4
+
5
+ module Options
6
+ def self.included: (::Module base) -> void
7
+
8
+ module ClassMethods
9
+ def cosmo_options: (**untyped opts) -> ::Hash[::Symbol, untyped]
10
+ def get_cosmo_options: () -> ::Hash[::Symbol, untyped]
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ module Cosmo
2
+ module API
3
+ class Cron
4
+ class Entry
5
+ SUBJECT_PREFIX: ::String
6
+
7
+ attr_reader class_name: ::String
8
+ attr_reader stream: ::String
9
+ attr_reader expression: ::String
10
+ attr_reader args: ::Array[untyped]
11
+ attr_reader timezone: ::String?
12
+ attr_reader name: ::String?
13
+
14
+ def self.normalize_expression: (untyped expr) -> ::String
15
+
16
+ def initialize: (class_name: ::String, stream: ::String, expression: ::String,
17
+ ?args: ::Array[untyped], ?timezone: ::String?, ?name: (::String | ::Symbol)?) -> void
18
+
19
+ def schedule_subject: () -> ::String
20
+ def target_subject: () -> ::String
21
+ def job_name: () -> ::String
22
+ def job_payload: () -> ::String
23
+ def as_json: () -> Hash[Symbol, untyped]
24
+ def to_s: () -> ::String
25
+ alias inspect to_s
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,25 @@
1
+ module Cosmo
2
+ module API
3
+ class Cron
4
+ def all: () -> ::Array[Hash[Symbol, untyped]]
5
+
6
+ def upsert!: (?Cosmo::API::Cron::Entry schedule_obj,
7
+ ?class_name: ::String?,
8
+ ?stream: ::String?,
9
+ ?expression: ::String?,
10
+ ?args: ::Array[untyped],
11
+ ?timezone: ::String?,
12
+ ?name: ::String?) -> Hash[Symbol, untyped]?
13
+
14
+ def delete!: (::String subject) -> void
15
+
16
+ def run_now!: (::String schedule_subject) -> void
17
+
18
+ private
19
+
20
+ def schedules_from_stream: (::String stream_name) -> ::Array[Hash[Symbol, untyped]]
21
+ def build_from_nats: (::String stream_name, ::String subject) -> Hash[Symbol, untyped]?
22
+ def name_from_subject: (::String subject) -> ::String?
23
+ end
24
+ end
25
+ end
data/sig/cosmo/api/kv.rbs CHANGED
@@ -5,11 +5,13 @@ module Cosmo
5
5
  @options: Hash[Symbol, untyped]
6
6
  @kv: untyped
7
7
 
8
+ attr_reader kv: untyped
9
+
8
10
  def initialize: (::String name, ?Hash[Symbol, untyped]? options) -> void
9
11
 
10
- def set: (::String | ::Integer key, ::String value) -> untyped
12
+ def set: (::String | ::Integer key, untyped value, ?ttl: ::Integer?) -> untyped
11
13
 
12
- def get: (::String | ::Integer key) -> ::String?
14
+ def get: (::String | ::Integer key) -> untyped
13
15
 
14
16
  def delete: (::String | ::Integer key) -> untyped
15
17
 
@@ -21,10 +23,6 @@ module Cosmo
21
23
 
22
24
  def count: () -> ::Integer
23
25
  alias size count
24
-
25
- private
26
-
27
- def kv: () -> untyped
28
26
  end
29
27
  end
30
28
  end
@@ -44,6 +44,12 @@ module Cosmo
44
44
 
45
45
  private
46
46
 
47
+ def scan_range: () -> [::Integer, ::Integer, Array[::String]]
48
+
49
+ def next_candidate: (Array[::String] subjects, Hash[::String, Job?] candidates, ::Integer current) -> [::String, Job]?
50
+
51
+ def next_message: (::String subject, ::Integer seq) -> Job?
52
+
47
53
  def client: () -> Client
48
54
  end
49
55
  end
data/sig/cosmo/client.rbs CHANGED
@@ -23,6 +23,10 @@ module Cosmo
23
23
 
24
24
  def update_stream: (::String | Symbol name, Hash[Symbol, untyped] config) -> untyped
25
25
 
26
+ def setup_stream: (::String name, Hash[Symbol, untyped] config) -> untyped
27
+
28
+ def cron_subjects_in_stream: (::String stream_name, ::String filter) -> Array[::String]
29
+
26
30
  def list_streams: () -> Array[Hash[::String, untyped]]
27
31
 
28
32
  def pause_stream: (::String name) -> void
@@ -41,8 +45,12 @@ module Cosmo
41
45
 
42
46
  def purge: (::String stream_name, ::String? subject) -> ::Integer?
43
47
 
44
- def kv: (::String name, **untyped opts) -> NATS::KeyValue
48
+ def kv: (::String name, ?allow_msg_ttl: bool, **untyped opts) -> untyped
45
49
 
46
50
  def close: -> void
51
+
52
+ private
53
+
54
+ def create_kv_with_msg_ttl: (::String name, **untyped opts) -> untyped
47
55
  end
48
56
  end
@@ -1,7 +1,7 @@
1
1
  module Cosmo
2
2
  module Job
3
3
  class Data
4
- DEFAULTS: { stream: Symbol, retry: Integer | bool, dead: bool }
4
+ DEFAULTS: { stream: Symbol, retry: Integer, dead: bool, limit: nil }
5
5
 
6
6
  @class_name: ::String
7
7
  @args: Array[untyped]
@@ -0,0 +1,18 @@
1
+ module Cosmo
2
+ module Job
3
+ class Limit
4
+ BUCKET: ::String
5
+
6
+ self.@instance: Limit
7
+
8
+ def self.instance: () -> Limit
9
+
10
+ def initialize: () -> void
11
+
12
+ def acquire: (::String key, jid: ::String, limit: ::Integer, duration: ::Integer) -> ::String?
13
+
14
+ def release: (::String slot) -> void
15
+ end
16
+ end
17
+ end
18
+
@@ -17,7 +17,7 @@ module Cosmo
17
17
 
18
18
  def process: (Array[untyped] messages, untyped processor) -> void
19
19
 
20
- def handle_failure: (untyped message, Hash[Symbol, untyped] data) -> void
20
+ def handle_failure: (untyped message, Hash[Symbol, untyped] data) -> bool
21
21
 
22
22
  def subscribe: (Symbol stream_name, Hash[Symbol, untyped] config) -> [untyped, Hash[Symbol, untyped], nil]
23
23
 
@@ -26,6 +26,8 @@ module Cosmo
26
26
  def move_message: (untyped message, ?Hash[Symbol, untyped]? data) -> void
27
27
 
28
28
  def with_stats: (untyped message) { () -> untyped } -> void
29
+
30
+ def acquire_concurrency_slot: (untyped worker_class, untyped message, Hash[Symbol, untyped] data) -> (::String | false)
29
31
  end
30
32
  end
31
33
  end
data/sig/cosmo/job.rbs CHANGED
@@ -5,7 +5,14 @@ module Cosmo
5
5
  module ClassMethods
6
6
  @default_options: Hash[Symbol, untyped]
7
7
 
8
- def options: (?stream: Symbol?, ?retry: Integer?, ?dead: bool?) -> Hash[Symbol, untyped]
8
+ def options: (**untyped config) -> Hash[Symbol, untyped]
9
+ alias cosmo_options options
10
+
11
+ def concurrency_options: () -> { limit: Integer, key: Proc?, duration: Integer }?
12
+
13
+ def concurrency_key: (Array[untyped] args) -> ::String?
14
+
15
+ def limits_concurrency?: () -> bool
9
16
 
10
17
  def perform: (*untyped args, ?async: bool, **untyped options) -> (::String | nil)
11
18
 
@@ -24,9 +31,7 @@ module Cosmo
24
31
  def client: () -> Client
25
32
  end
26
33
 
27
- attr_reader jid: ::String
28
-
29
- def jid=: (::String) -> ::String
34
+ attr_accessor jid: ::String
30
35
 
31
36
  def perform: (*untyped) -> untyped
32
37
 
@@ -0,0 +1,4 @@
1
+ module Cosmo
2
+ class Railtie < ::Rails::Railtie
3
+ end
4
+ end
@@ -3,12 +3,16 @@ module Cosmo
3
3
  module Hash
4
4
  def self.symbolize_keys!: (untyped obj) -> (::Hash[Symbol, untyped] | Array[untyped] | untyped)
5
5
 
6
+ def self.stringify_keys: (untyped obj) -> (::Hash[String, untyped] | Array[untyped] | untyped)
7
+
6
8
  def self.dup: [T] (T hash) -> T
7
9
 
8
10
  def self.set: (::Hash[untyped, untyped] hash, *untyped keys, value: untyped) -> untyped
9
11
 
10
12
  def symbolize_keys!: (untyped obj) -> (::Hash[Symbol, untyped] | Array[untyped] | untyped)
11
13
 
14
+ def stringify_keys: (untyped obj) -> (::Hash[String, untyped] | Array[untyped] | untyped)
15
+
12
16
  def dup: [T] (T hash) -> T
13
17
 
14
18
  def set: (::Hash[untyped, untyped] hash, *untyped keys, value: untyped) -> untyped
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cosmonats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dmitry Vorotilin
@@ -63,9 +63,15 @@ files:
63
63
  - README.md
64
64
  - bin/cosmo
65
65
  - lib/cosmo.rb
66
+ - lib/cosmo/active_job.rb
67
+ - lib/cosmo/active_job/adapter.rb
68
+ - lib/cosmo/active_job/executor.rb
69
+ - lib/cosmo/active_job/options.rb
66
70
  - lib/cosmo/api.rb
67
71
  - lib/cosmo/api/busy.rb
68
72
  - lib/cosmo/api/counter.rb
73
+ - lib/cosmo/api/cron.rb
74
+ - lib/cosmo/api/cron/entry.rb
69
75
  - lib/cosmo/api/job.rb
70
76
  - lib/cosmo/api/kv.rb
71
77
  - lib/cosmo/api/stats.rb
@@ -76,10 +82,14 @@ files:
76
82
  - lib/cosmo/engine.rb
77
83
  - lib/cosmo/job.rb
78
84
  - lib/cosmo/job/data.rb
85
+ - lib/cosmo/job/limit.rb
79
86
  - lib/cosmo/job/processor.rb
80
87
  - lib/cosmo/logger.rb
81
88
  - lib/cosmo/processor.rb
82
89
  - lib/cosmo/publisher.rb
90
+ - lib/cosmo/railtie.rb
91
+ - lib/cosmo/sentry/auto.rb
92
+ - lib/cosmo/sentry/job_processor_middleware.rb
83
93
  - lib/cosmo/stream.rb
84
94
  - lib/cosmo/stream/data.rb
85
95
  - lib/cosmo/stream/message.rb
@@ -102,16 +112,20 @@ files:
102
112
  - lib/cosmo/web/context.rb
103
113
  - lib/cosmo/web/controllers/actions.rb
104
114
  - lib/cosmo/web/controllers/application.rb
115
+ - lib/cosmo/web/controllers/crons.rb
105
116
  - lib/cosmo/web/controllers/jobs.rb
106
117
  - lib/cosmo/web/controllers/streams.rb
107
118
  - lib/cosmo/web/helpers/application.rb
108
119
  - lib/cosmo/web/renderer.rb
109
120
  - lib/cosmo/web/views/actions/index.erb
121
+ - lib/cosmo/web/views/crons/_table.erb
122
+ - lib/cosmo/web/views/crons/index.erb
110
123
  - lib/cosmo/web/views/jobs/_busy.erb
111
124
  - lib/cosmo/web/views/jobs/_dead.erb
112
125
  - lib/cosmo/web/views/jobs/_enqueued.erb
113
126
  - lib/cosmo/web/views/jobs/_scheduled.erb
114
127
  - lib/cosmo/web/views/jobs/_stats.erb
128
+ - lib/cosmo/web/views/jobs/_tabs.erb
115
129
  - lib/cosmo/web/views/jobs/busy.erb
116
130
  - lib/cosmo/web/views/jobs/dead.erb
117
131
  - lib/cosmo/web/views/jobs/enqueued.erb
@@ -126,8 +140,13 @@ files:
126
140
  - lib/cosmo/web/views/streams/info.erb
127
141
  - lib/cosmonats.rb
128
142
  - sig/cosmo.rbs
143
+ - sig/cosmo/active_job/adapter.rbs
144
+ - sig/cosmo/active_job/executor.rbs
145
+ - sig/cosmo/active_job/options.rbs
129
146
  - sig/cosmo/api/busy.rbs
130
147
  - sig/cosmo/api/counter.rbs
148
+ - sig/cosmo/api/cron.rbs
149
+ - sig/cosmo/api/cron/entry.rbs
131
150
  - sig/cosmo/api/job.rbs
132
151
  - sig/cosmo/api/kv.rbs
133
152
  - sig/cosmo/api/stats.rbs
@@ -138,10 +157,12 @@ files:
138
157
  - sig/cosmo/engine.rbs
139
158
  - sig/cosmo/job.rbs
140
159
  - sig/cosmo/job/data.rbs
160
+ - sig/cosmo/job/limit.rbs
141
161
  - sig/cosmo/job/processor.rbs
142
162
  - sig/cosmo/logger.rbs
143
163
  - sig/cosmo/processor.rbs
144
164
  - sig/cosmo/publisher.rbs
165
+ - sig/cosmo/railtie.rbs
145
166
  - sig/cosmo/stream.rbs
146
167
  - sig/cosmo/stream/data.rbs
147
168
  - sig/cosmo/stream/message.rbs
@@ -178,7 +199,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
178
199
  - !ruby/object:Gem::Version
179
200
  version: '0'
180
201
  requirements: []
181
- rubygems_version: 4.0.12
202
+ rubygems_version: 4.0.16
182
203
  specification_version: 4
183
204
  summary: Lightweight background and stream processing
184
205
  test_files: []