cosmonats 0.3.0 → 0.4.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.
Files changed (62) 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 +10 -5
  13. data/lib/cosmo/api.rb +1 -0
  14. data/lib/cosmo/cli.rb +27 -10
  15. data/lib/cosmo/client.rb +48 -2
  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 +49 -5
  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/stream/processor.rb +2 -2
  24. data/lib/cosmo/stream.rb +2 -1
  25. data/lib/cosmo/utils/hash.rb +13 -0
  26. data/lib/cosmo/utils/overrides.rb +1 -1
  27. data/lib/cosmo/version.rb +1 -1
  28. data/lib/cosmo/web/assets/app.css +42 -0
  29. data/lib/cosmo/web/controllers/crons.rb +41 -0
  30. data/lib/cosmo/web/controllers/jobs.rb +7 -3
  31. data/lib/cosmo/web/controllers/streams.rb +1 -1
  32. data/lib/cosmo/web/helpers/application.rb +4 -0
  33. data/lib/cosmo/web/views/actions/index.erb +1 -1
  34. data/lib/cosmo/web/views/crons/_table.erb +58 -0
  35. data/lib/cosmo/web/views/crons/index.erb +10 -0
  36. data/lib/cosmo/web/views/jobs/_busy.erb +54 -49
  37. data/lib/cosmo/web/views/jobs/_dead.erb +70 -65
  38. data/lib/cosmo/web/views/jobs/_enqueued.erb +82 -56
  39. data/lib/cosmo/web/views/jobs/_scheduled.erb +53 -48
  40. data/lib/cosmo/web/views/jobs/_tabs.erb +6 -0
  41. data/lib/cosmo/web/views/jobs/busy.erb +8 -6
  42. data/lib/cosmo/web/views/jobs/dead.erb +6 -5
  43. data/lib/cosmo/web/views/jobs/enqueued.erb +8 -6
  44. data/lib/cosmo/web/views/jobs/index.erb +1 -1
  45. data/lib/cosmo/web/views/jobs/scheduled.erb +6 -5
  46. data/lib/cosmo/web/views/layout.erb +1 -1
  47. data/lib/cosmo/web.rb +5 -0
  48. data/lib/cosmo.rb +1 -0
  49. data/sig/cosmo/active_job/adapter.rbs +13 -0
  50. data/sig/cosmo/active_job/executor.rbs +9 -0
  51. data/sig/cosmo/active_job/options.rbs +14 -0
  52. data/sig/cosmo/api/cron/entry.rbs +30 -0
  53. data/sig/cosmo/api/cron.rbs +25 -0
  54. data/sig/cosmo/api/kv.rbs +4 -6
  55. data/sig/cosmo/client.rbs +9 -1
  56. data/sig/cosmo/job/data.rbs +1 -1
  57. data/sig/cosmo/job/limit.rbs +18 -0
  58. data/sig/cosmo/job/processor.rbs +3 -1
  59. data/sig/cosmo/job.rbs +9 -4
  60. data/sig/cosmo/railtie.rbs +4 -0
  61. data/sig/cosmo/utils/hash.rbs +4 -0
  62. metadata +20 -1
@@ -1,65 +1,70 @@
1
- <% if @jobs.empty? -%>
2
- <div class="alert alert-success">No dead jobs found</div>
3
- <% else -%>
4
- <div class="table-container">
5
- <table>
6
- <thead>
7
- <tr>
8
- <th>Job</th>
9
- <th>JID[Args]</th>
10
- <th>Stream</th>
11
- <th>Error</th>
12
- <th>Failed</th>
13
- <th>Actions</th>
14
- </tr>
15
- </thead>
16
- <tbody>
17
- <% @jobs.each do |job| -%>
18
- <tr class="dead-row" id="dead-row-<%= job.seq %>">
19
- <td>
20
- <div class="job-class">
21
- <%= h(job.data[:class].to_s) %>
22
- </div>
23
- </td>
24
- <td>
25
- <div class="job-id">
26
- <details>
27
- <summary>
28
- <code><%= h(job.data[:jid].to_s) %></code>
29
- </summary>
30
- <code><%= h((JSON.pretty_generate(job.data[:args]) rescue job.data[:args].to_s)) %></code>
31
- </details>
32
- </div>
33
- </td>
34
- <td>
35
- <code><%= h(job.stream) %></code>
36
- </td>
37
- <td style="max-width: 400px;">
38
- <% if job.data[:error] -%>
39
- <div class="error-message">
40
- <strong><%= h(job.data[:error].to_s.split(":").first || "Error") %></strong>
41
- <p><%= h(job.data[:error]) %></p>
42
- </div>
43
- <% end -%>
44
- </td>
45
- <td style="white-space: nowrap;">
46
- <time><%= h(job.timestamp) %></time>
47
- </td>
48
- <td>
49
- <a hx-patch="<%= url_for("/jobs/retry/#{job.seq}") %>"
50
- hx-target="#dead-row-<%= job.seq %>"
51
- hx-swap="innerHTML"
52
- class="btn btn-primary"
53
- style="width: 100%; text-align: center; margin-bottom: 3px">&#x21BB; Retry</a>
54
- <a hx-delete="<%= url_for("/jobs/delete/#{job.seq}") %>"
55
- hx-target="#dead-row-<%= job.seq %>"
56
- hx-swap="innerHTML"
57
- class="btn btn-danger"
58
- style="width: 100%; text-align: center; margin-bottom: 3px">&#x2715; Delete</a>
59
- </td>
60
- </tr>
61
- <% end -%>
62
- </tbody>
63
- </table>
64
- </div>
65
- <% end -%>
1
+ <div id="dead-poller"
2
+ hx-get="<%= url_for('/jobs/_dead') %>"
3
+ hx-trigger="every 5s"
4
+ hx-swap="outerHTML">
5
+ <% if @jobs.empty? -%>
6
+ <div class="alert alert-success">No dead jobs found</div>
7
+ <% else -%>
8
+ <div class="table-container">
9
+ <table>
10
+ <thead>
11
+ <tr>
12
+ <th>Job</th>
13
+ <th>JID[Args]</th>
14
+ <th>Stream</th>
15
+ <th>Error</th>
16
+ <th>Failed</th>
17
+ <th>Actions</th>
18
+ </tr>
19
+ </thead>
20
+ <tbody>
21
+ <% @jobs.each do |job| -%>
22
+ <tr class="dead-row" id="dead-row-<%= job.seq %>">
23
+ <td>
24
+ <div class="job-class">
25
+ <%= h(job.data[:class].to_s) %>
26
+ </div>
27
+ </td>
28
+ <td>
29
+ <div class="job-id">
30
+ <details>
31
+ <summary>
32
+ <code><%= h(job.data[:jid].to_s) %></code>
33
+ </summary>
34
+ <code><%= h((JSON.pretty_generate(job.data[:args]) rescue job.data[:args].to_s)) %></code>
35
+ </details>
36
+ </div>
37
+ </td>
38
+ <td>
39
+ <code><%= h(job.stream) %></code>
40
+ </td>
41
+ <td style="max-width: 400px;">
42
+ <% if job.data[:error] -%>
43
+ <div class="error-message">
44
+ <strong><%= h(job.data[:error].to_s.split(":").first || "Error") %></strong>
45
+ <p><%= h(job.data[:error]) %></p>
46
+ </div>
47
+ <% end -%>
48
+ </td>
49
+ <td style="white-space: nowrap;">
50
+ <time><%= h(job.timestamp) %></time>
51
+ </td>
52
+ <td>
53
+ <a hx-patch="<%= url_for("/jobs/retry/#{job.seq}") %>"
54
+ hx-target="#dead-row-<%= job.seq %>"
55
+ hx-swap="innerHTML"
56
+ class="btn btn-primary"
57
+ style="width: 100%; text-align: center; margin-bottom: 3px">&#x21BB; Retry</a>
58
+ <a hx-delete="<%= url_for("/jobs/delete/#{job.seq}") %>"
59
+ hx-target="#dead-row-<%= job.seq %>"
60
+ hx-swap="innerHTML"
61
+ class="btn btn-danger"
62
+ style="width: 100%; text-align: center; margin-bottom: 3px">&#x2715; Delete</a>
63
+ </td>
64
+ </tr>
65
+ <% end -%>
66
+ </tbody>
67
+ </table>
68
+ </div>
69
+ <% end -%>
70
+ </div>
@@ -1,60 +1,86 @@
1
- <div class="nav">
2
- <% @stream_names.each do |stream_name| -%>
3
- <button hx-get="<%= url_for('/jobs/enqueued', { stream_name: }) %>"
4
- hx-target="#content"
5
- hx-swap="innerHTML"
6
- hx-push-url="true"
7
- class="btn <%= "btn-primary" if @stream_name.to_s == stream_name.to_s %>">
8
- <%= h(stream_name) %>
9
- </button>
1
+ <div id="enqueued-poller">
2
+ <div class="nav">
3
+ <% @stream_names.each do |stream_name| -%>
4
+ <button hx-get="<%= url_for('/jobs/enqueued', { stream_name: }) %>"
5
+ hx-target="#content"
6
+ hx-swap="innerHTML"
7
+ hx-push-url="true"
8
+ class="btn <%= "btn-primary" if @stream_name.to_s == stream_name.to_s %>">
9
+ <%= h(stream_name) %>
10
+ </button>
11
+ <% end -%>
12
+ </div>
13
+
14
+ <div class="pending">
15
+ <span></span>
16
+ <span class="text-muted"><%= @total %> message(s) pending</span>
17
+ </div>
18
+
19
+ <% if @jobs.empty? -%>
20
+ <div class="alert alert-success">Stream <code><%= h(@stream_name) %></code> is empty</div>
21
+ <% else -%>
22
+ <div class="table-container">
23
+ <table>
24
+ <thead>
25
+ <tr>
26
+ <th>Job</th>
27
+ <th>JID[Args]</th>
28
+ <th>Stream</th>
29
+ <th>Seq</th>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ <% @jobs.each do |job| -%>
34
+ <tr>
35
+ <td>
36
+ <div class="job-class">
37
+ <%= h(job.data[:class].to_s) %>
38
+ </div>
39
+ </td>
40
+ <td>
41
+ <div class="job-id">
42
+ <details>
43
+ <summary>
44
+ <code><%= h(job.data[:jid].to_s) %></code>
45
+ </summary>
46
+ <code><%= h((JSON.pretty_generate(job.data[:args]) rescue job.data[:args].to_s)) %></code>
47
+ </details>
48
+ </div>
49
+ </td>
50
+ <td>
51
+ <code><%= h(job.stream) %></code>
52
+ </td>
53
+ <td>
54
+ <code><%= job.seq %></code>
55
+ </td>
56
+ </tr>
57
+ <% end -%>
58
+ </tbody>
59
+ </table>
60
+ </div>
10
61
  <% end -%>
11
- </div>
12
62
 
13
- <div class="pending">
14
- <span></span>
15
- <span class="text-muted"><%= @total %> message(s) pending</span>
16
- </div>
63
+ <% if @total_pages > 1 -%>
64
+ <div class="pagination">
65
+ <% if @page > 1 -%>
66
+ <a hx-get="<%= url_for('/jobs/_enqueued', stream_name: @stream_name, page: @page - 1, limit: @limit) %>"
67
+ hx-target="#enqueued-poller"
68
+ hx-swap="outerHTML"
69
+ class="btn">&#x2190; Prev</a>
70
+ <% else -%>
71
+ <span class="btn btn-disabled">&#x2190; Prev</span>
72
+ <% end -%>
73
+
74
+ <span class="text-muted">Page <%= @page %> of <%= @total_pages %></span>
17
75
 
18
- <% if @jobs.empty? -%>
19
- <div class="alert alert-success">Stream <code><%= h(@stream_name) %></code> is empty</div>
20
- <% else -%>
21
- <div class="table-container">
22
- <table>
23
- <thead>
24
- <tr>
25
- <th>Job</th>
26
- <th>JID[Args]</th>
27
- <th>Stream</th>
28
- <th>Seq</th>
29
- </tr>
30
- </thead>
31
- <tbody>
32
- <% @jobs.each do |job| -%>
33
- <tr>
34
- <td>
35
- <div class="job-class">
36
- <%= h(job.data[:class].to_s) %>
37
- </div>
38
- </td>
39
- <td>
40
- <div class="job-id">
41
- <details>
42
- <summary>
43
- <code><%= h(job.data[:jid].to_s) %></code>
44
- </summary>
45
- <code><%= h((JSON.pretty_generate(job.data[:args]) rescue job.data[:args].to_s)) %></code>
46
- </details>
47
- </div>
48
- </td>
49
- <td>
50
- <code><%= h(job.stream) %></code>
51
- </td>
52
- <td>
53
- <code><%= job.seq %></code>
54
- </td>
55
- </tr>
56
- <% end -%>
57
- </tbody>
58
- </table>
76
+ <% if @page < @total_pages -%>
77
+ <a hx-get="<%= url_for('/jobs/_enqueued', stream_name: @stream_name, page: @page + 1, limit: @limit) %>"
78
+ hx-target="#enqueued-poller"
79
+ hx-swap="outerHTML"
80
+ class="btn">Next &#x2192;</a>
81
+ <% else -%>
82
+ <span class="btn btn-disabled">Next &#x2192;</span>
83
+ <% end -%>
59
84
  </div>
60
- <% end -%>
85
+ <% end -%>
86
+ </div>
@@ -1,49 +1,54 @@
1
- <div class="pending">
2
- <span></span>
3
- <span class="text-muted"><%= @total %> job(s) scheduled</span>
4
- </div>
5
-
6
- <% if @jobs.empty? -%>
7
- <div class="alert alert-success">No scheduled jobs found</div>
8
- <% else -%>
9
- <div class="table-container">
10
- <table>
11
- <thead>
12
- <tr>
13
- <th>Job</th>
14
- <th>JID[Args]</th>
15
- <th>Stream</th>
16
- <th>When</th>
17
- </tr>
18
- </thead>
19
- <tbody>
20
- <% @jobs.each do |job| -%>
21
- <tr>
22
- <td>
23
- <div class="job-class">
24
- <%= h(job.data[:class].to_s) %>
25
- </div>
26
- </td>
27
- <td>
28
- <div class="job-id">
29
- <details>
30
- <summary>
31
- <code><%= h(job.data[:jid].to_s) %></code>
32
- </summary>
33
- <code><%= h((JSON.pretty_generate(job.data[:args]) rescue job.data[:args].to_s)) %></code>
34
- </details>
35
- </div>
36
- </td>
37
- <td>
38
- <code><%= h(job.x_stream) %></code>
39
- </td>
40
- <td style="white-space: nowrap;">
41
- <div class="time-badge"><%= h(time_until(job.execute_at)) %></div>
42
- <time><%= h(format_timestamp(job.execute_at)) %></time>
43
- </td>
44
- </tr>
45
- <% end -%>
46
- </tbody>
47
- </table>
1
+ <div id="scheduled-poller"
2
+ hx-get="<%= url_for('/jobs/_scheduled') %>"
3
+ hx-trigger="every 5s"
4
+ hx-swap="outerHTML">
5
+ <div class="pending">
6
+ <span></span>
7
+ <span class="text-muted"><%= @total %> job(s) scheduled</span>
48
8
  </div>
49
- <% end -%>
9
+
10
+ <% if @jobs.empty? -%>
11
+ <div class="alert alert-success">No scheduled jobs found</div>
12
+ <% else -%>
13
+ <div class="table-container">
14
+ <table>
15
+ <thead>
16
+ <tr>
17
+ <th>Job</th>
18
+ <th>JID[Args]</th>
19
+ <th>Stream</th>
20
+ <th>When</th>
21
+ </tr>
22
+ </thead>
23
+ <tbody>
24
+ <% @jobs.each do |job| -%>
25
+ <tr>
26
+ <td>
27
+ <div class="job-class">
28
+ <%= h(job.data[:class].to_s) %>
29
+ </div>
30
+ </td>
31
+ <td>
32
+ <div class="job-id">
33
+ <details>
34
+ <summary>
35
+ <code><%= h(job.data[:jid].to_s) %></code>
36
+ </summary>
37
+ <code><%= h((JSON.pretty_generate(job.data[:args]) rescue job.data[:args].to_s)) %></code>
38
+ </details>
39
+ </div>
40
+ </td>
41
+ <td>
42
+ <code><%= h(job.x_stream) %></code>
43
+ </td>
44
+ <td style="white-space: nowrap;">
45
+ <div class="time-badge"><%= h(time_until(job.execute_at)) %></div>
46
+ <time><%= h(format_timestamp(job.execute_at)) %></time>
47
+ </td>
48
+ </tr>
49
+ <% end -%>
50
+ </tbody>
51
+ </table>
52
+ </div>
53
+ <% end -%>
54
+ </div>
@@ -0,0 +1,6 @@
1
+ <nav class="tabs">
2
+ <a href="<%= url_for('/jobs') %>"
3
+ class="<%= 'active' if path_prefix?('/jobs') %>">&#x1F4CB; Dashboard</a>
4
+ <a href="<%= url_for('/crons') %>"
5
+ class="<%= 'active' if path_prefix?('/crons') %>">&#x23F0; Crons</a>
6
+ </nav>
@@ -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/_busy') %>"
12
- hx-trigger="load, every 5s"
13
- hx-swap="innerHTML">
14
- <div class="alert alert-info">Loading busy jobs&hellip;</div>
10
+ <div id="content">
11
+ <div id="busy-poller"
12
+ hx-get="<%= url_for('/jobs/_busy') %>"
13
+ hx-trigger="load"
14
+ hx-swap="outerHTML">
15
+ <div class="alert alert-info">Loading busy 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"
@@ -8,10 +8,11 @@
8
8
  </div>
9
9
 
10
10
  <div id="content">
11
- <div hx-get="<%= url_for('/jobs/_dead') %>"
12
- hx-trigger="load, every 5s"
13
- hx-swap="innerHTML">
14
- <div class="alert alert-info">Loading dead jobs…</div>
11
+ <div id="dead-poller"
12
+ hx-get="<%= url_for('/jobs/_dead') %>"
13
+ hx-trigger="load"
14
+ hx-swap="outerHTML">
15
+ <div class="alert alert-info">Loading dead jobs&hellip;</div>
15
16
  </div>
16
17
  </div>
17
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"
@@ -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>
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