pgbus 0.1.5 → 0.1.7
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/README.md +326 -11
- data/app/controllers/pgbus/api/insights_controller.rb +16 -0
- data/app/controllers/pgbus/insights_controller.rb +10 -0
- data/app/controllers/pgbus/locks_controller.rb +9 -0
- data/app/helpers/pgbus/application_helper.rb +28 -0
- data/app/models/pgbus/job_lock.rb +82 -0
- data/app/models/pgbus/job_stat.rb +94 -0
- data/app/views/layouts/pgbus/application.html.erb +31 -8
- data/app/views/pgbus/dashboard/_processes_table.html.erb +6 -6
- data/app/views/pgbus/dashboard/_queues_table.html.erb +6 -6
- data/app/views/pgbus/dashboard/_recent_failures.html.erb +5 -5
- data/app/views/pgbus/dashboard/_stats_cards.html.erb +20 -20
- data/app/views/pgbus/dashboard/show.html.erb +1 -1
- data/app/views/pgbus/dead_letter/_messages_table.html.erb +12 -12
- data/app/views/pgbus/dead_letter/index.html.erb +1 -1
- data/app/views/pgbus/dead_letter/show.html.erb +10 -10
- data/app/views/pgbus/events/index.html.erb +15 -15
- data/app/views/pgbus/events/show.html.erb +5 -5
- data/app/views/pgbus/insights/show.html.erb +161 -0
- data/app/views/pgbus/jobs/_enqueued_table.html.erb +13 -13
- data/app/views/pgbus/jobs/_failed_table.html.erb +7 -7
- data/app/views/pgbus/jobs/index.html.erb +1 -1
- data/app/views/pgbus/jobs/show.html.erb +10 -10
- data/app/views/pgbus/locks/index.html.erb +53 -0
- data/app/views/pgbus/outbox/index.html.erb +12 -12
- data/app/views/pgbus/processes/_processes_table.html.erb +6 -6
- data/app/views/pgbus/processes/index.html.erb +1 -1
- data/app/views/pgbus/queues/_queues_list.html.erb +5 -5
- data/app/views/pgbus/queues/index.html.erb +1 -1
- data/app/views/pgbus/queues/show.html.erb +7 -7
- data/app/views/pgbus/recurring_tasks/_tasks_table.html.erb +6 -6
- data/app/views/pgbus/recurring_tasks/index.html.erb +1 -1
- data/app/views/pgbus/recurring_tasks/show.html.erb +22 -22
- data/config/routes.rb +3 -0
- data/lib/generators/pgbus/add_job_locks_generator.rb +52 -0
- data/lib/generators/pgbus/add_job_stats_generator.rb +52 -0
- data/lib/generators/pgbus/add_outbox_generator.rb +1 -1
- data/lib/generators/pgbus/add_queue_states_generator.rb +1 -1
- data/lib/generators/pgbus/add_recurring_generator.rb +1 -1
- data/lib/generators/pgbus/install_generator.rb +1 -1
- data/lib/generators/pgbus/templates/add_job_locks.rb.erb +21 -0
- data/lib/generators/pgbus/templates/add_job_stats.rb.erb +18 -0
- data/lib/generators/pgbus/upgrade_pgmq_generator.rb +1 -1
- data/lib/pgbus/active_job/adapter.rb +58 -4
- data/lib/pgbus/active_job/executor.rb +45 -0
- data/lib/pgbus/client.rb +8 -22
- data/lib/pgbus/configuration.rb +6 -0
- data/lib/pgbus/engine.rb +1 -0
- data/lib/pgbus/process/consumer_priority.rb +64 -0
- data/lib/pgbus/process/dispatcher.rb +29 -0
- data/lib/pgbus/process/queue_lock.rb +87 -0
- data/lib/pgbus/process/supervisor.rb +6 -1
- data/lib/pgbus/process/wake_signal.rb +53 -0
- data/lib/pgbus/process/worker.rb +36 -6
- data/lib/pgbus/queue_factory.rb +62 -0
- data/lib/pgbus/uniqueness.rb +169 -0
- data/lib/pgbus/version.rb +1 -1
- data/lib/pgbus/web/data_source.rb +49 -0
- data/lib/pgbus.rb +1 -0
- metadata +17 -1
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<turbo-frame id="jobs-enqueued" data-auto-refresh src="<%= pgbus.jobs_path(request.query_parameters.merge(frame: 'enqueued')) %>">
|
|
2
2
|
<div>
|
|
3
|
-
<h2 class="text-lg font-semibold text-gray-900 mb-3">Enqueued Jobs</h2>
|
|
4
|
-
<div class="overflow-hidden rounded-lg bg-white shadow ring-1 ring-gray-200">
|
|
5
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
6
|
-
<thead class="bg-gray-50">
|
|
3
|
+
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-3">Enqueued Jobs</h2>
|
|
4
|
+
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
5
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
6
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
7
7
|
<tr>
|
|
8
8
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">ID</th>
|
|
9
9
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Job Class</th>
|
|
@@ -12,31 +12,31 @@
|
|
|
12
12
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Reads</th>
|
|
13
13
|
</tr>
|
|
14
14
|
</thead>
|
|
15
|
-
<tbody class="divide-y divide-gray-100">
|
|
15
|
+
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
16
16
|
<% @jobs.each do |j| %>
|
|
17
17
|
<% payload = pgbus_parse_message(j[:message]) %>
|
|
18
18
|
<tr>
|
|
19
19
|
<td colspan="5" class="p-0">
|
|
20
20
|
<details class="group">
|
|
21
|
-
<summary class="flex cursor-pointer hover:bg-gray-50 list-none">
|
|
22
|
-
<span class="w-16 shrink-0 px-4 py-3 text-sm font-mono text-gray-900"><%= j[:msg_id] %></span>
|
|
23
|
-
<span class="flex-1 px-4 py-3 text-sm font-medium text-gray-900"><%= payload["job_class"] || "—" %></span>
|
|
21
|
+
<summary class="flex cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900 list-none">
|
|
22
|
+
<span class="w-16 shrink-0 px-4 py-3 text-sm font-mono text-gray-900 dark:text-white"><%= j[:msg_id] %></span>
|
|
23
|
+
<span class="flex-1 px-4 py-3 text-sm font-medium text-gray-900 dark:text-white"><%= payload["job_class"] || "—" %></span>
|
|
24
24
|
<span class="w-40 shrink-0 px-4 py-3 text-sm text-gray-700"><%= j[:queue_name] %></span>
|
|
25
25
|
<span class="w-28 shrink-0 px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(j[:enqueued_at]) %></span>
|
|
26
26
|
<span class="w-16 shrink-0 px-4 py-3 text-sm text-gray-500"><%= j[:read_ct] %></span>
|
|
27
27
|
</summary>
|
|
28
|
-
<div class="px-4 pb-4 bg-gray-50 border-t border-gray-100">
|
|
28
|
+
<div class="px-4 pb-4 bg-gray-50 dark:bg-gray-900 border-t border-gray-100">
|
|
29
29
|
<div class="flex items-center mt-3 mb-3">
|
|
30
30
|
<span class="text-xs font-mono text-gray-400">Job ID: <%= payload["job_id"] %></span>
|
|
31
31
|
</div>
|
|
32
32
|
<div class="grid grid-cols-2 gap-4 mb-3">
|
|
33
33
|
<div>
|
|
34
34
|
<span class="text-xs font-medium text-gray-500">Arguments</span>
|
|
35
|
-
<pre class="text-xs text-gray-700 bg-white rounded p-2 mt-1 overflow-x-auto max-h-40"><%= JSON.pretty_generate(payload["arguments"] || []) rescue "—" %></pre>
|
|
35
|
+
<pre class="text-xs text-gray-700 bg-white dark:bg-gray-800 rounded p-2 mt-1 overflow-x-auto max-h-40"><%= JSON.pretty_generate(payload["arguments"] || []) rescue "—" %></pre>
|
|
36
36
|
</div>
|
|
37
37
|
<div>
|
|
38
38
|
<span class="text-xs font-medium text-gray-500">Metadata</span>
|
|
39
|
-
<div class="text-xs text-gray-600 bg-white rounded p-2 mt-1 space-y-1">
|
|
39
|
+
<div class="text-xs text-gray-600 bg-white dark:bg-gray-800 rounded p-2 mt-1 space-y-1">
|
|
40
40
|
<% if payload["queue_name"] %><p><strong>Queue:</strong> <%= payload["queue_name"] %></p><% end %>
|
|
41
41
|
<% if payload["priority"] %><p><strong>Priority:</strong> <%= payload["priority"] %></p><% end %>
|
|
42
42
|
<% if payload["locale"] %><p><strong>Locale:</strong> <%= payload["locale"] %></p><% end %>
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
</div>
|
|
50
50
|
<details class="mt-2">
|
|
51
51
|
<summary class="text-xs font-medium text-gray-500 cursor-pointer hover:text-gray-700">Full JSON payload</summary>
|
|
52
|
-
<pre class="text-xs text-gray-600 bg-white rounded p-2 mt-1 overflow-x-auto max-h-96"><%= JSON.pretty_generate(payload) rescue j[:message] %></pre>
|
|
52
|
+
<pre class="text-xs text-gray-600 bg-white dark:bg-gray-800 rounded p-2 mt-1 overflow-x-auto max-h-96"><%= JSON.pretty_generate(payload) rescue j[:message] %></pre>
|
|
53
53
|
</details>
|
|
54
54
|
<% if j[:headers] %>
|
|
55
55
|
<details class="mt-2">
|
|
56
56
|
<summary class="text-xs font-medium text-gray-500 cursor-pointer hover:text-gray-700">Headers</summary>
|
|
57
|
-
<pre class="text-xs text-gray-600 bg-white rounded p-2 mt-1 overflow-x-auto"><%= JSON.pretty_generate(JSON.parse(j[:headers])) rescue j[:headers] %></pre>
|
|
57
|
+
<pre class="text-xs text-gray-600 bg-white dark:bg-gray-800 rounded p-2 mt-1 overflow-x-auto"><%= JSON.pretty_generate(JSON.parse(j[:headers])) rescue j[:headers] %></pre>
|
|
58
58
|
</details>
|
|
59
59
|
<% end %>
|
|
60
60
|
</div>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<turbo-frame id="jobs-failed" data-auto-refresh src="<%= pgbus.jobs_path(frame: 'failed') %>">
|
|
2
2
|
<div class="mb-8">
|
|
3
|
-
<h2 class="text-lg font-semibold text-gray-900 mb-3">Failed Jobs</h2>
|
|
4
|
-
<div class="overflow-hidden rounded-lg bg-white shadow ring-1 ring-gray-200">
|
|
5
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
6
|
-
<thead class="bg-gray-50">
|
|
3
|
+
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-3">Failed Jobs</h2>
|
|
4
|
+
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
5
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
6
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
7
7
|
<tr>
|
|
8
8
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">ID</th>
|
|
9
9
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Queue</th>
|
|
@@ -13,10 +13,10 @@
|
|
|
13
13
|
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500">Actions</th>
|
|
14
14
|
</tr>
|
|
15
15
|
</thead>
|
|
16
|
-
<tbody class="divide-y divide-gray-100">
|
|
16
|
+
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
17
17
|
<% @failed.each do |f| %>
|
|
18
|
-
<tr class="hover:bg-gray-50">
|
|
19
|
-
<td class="px-4 py-3 text-sm font-mono text-gray-900">
|
|
18
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
19
|
+
<td class="px-4 py-3 text-sm font-mono text-gray-900 dark:text-white">
|
|
20
20
|
<%= link_to f["id"], pgbus.job_path(f["id"]), class: "text-indigo-600 hover:text-indigo-500", data: { turbo_frame: "_top" } %>
|
|
21
21
|
</td>
|
|
22
22
|
<td class="px-4 py-3 text-sm text-gray-700"><%= f["queue_name"] %></td>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="flex items-center justify-between mb-6">
|
|
2
|
-
<h1 class="text-2xl font-bold text-gray-900">Jobs</h1>
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Jobs</h1>
|
|
3
3
|
<% if @failed.any? %>
|
|
4
4
|
<div class="flex space-x-2">
|
|
5
5
|
<%= button_to "Retry All", pgbus.retry_all_jobs_path, method: :post,
|
|
@@ -3,17 +3,17 @@
|
|
|
3
3
|
</div>
|
|
4
4
|
|
|
5
5
|
<% if @job %>
|
|
6
|
-
<h1 class="text-2xl font-bold text-gray-900 mb-6">Failed Job #<%= @job["id"] %></h1>
|
|
6
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white mb-6">Failed Job #<%= @job["id"] %></h1>
|
|
7
7
|
|
|
8
|
-
<div class="rounded-lg bg-white shadow ring-1 ring-gray-200 p-6 mb-6">
|
|
8
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700 p-6 mb-6">
|
|
9
9
|
<dl class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
10
10
|
<div>
|
|
11
11
|
<dt class="text-sm font-medium text-gray-500">Queue</dt>
|
|
12
|
-
<dd class="text-sm text-gray-900"><%= @job["queue_name"] %></dd>
|
|
12
|
+
<dd class="text-sm text-gray-900 dark:text-white"><%= @job["queue_name"] %></dd>
|
|
13
13
|
</div>
|
|
14
14
|
<div>
|
|
15
15
|
<dt class="text-sm font-medium text-gray-500">Failed At</dt>
|
|
16
|
-
<dd class="text-sm text-gray-900"><%= @job["failed_at"] %></dd>
|
|
16
|
+
<dd class="text-sm text-gray-900 dark:text-white"><%= @job["failed_at"] %></dd>
|
|
17
17
|
</div>
|
|
18
18
|
<div>
|
|
19
19
|
<dt class="text-sm font-medium text-gray-500">Error Class</dt>
|
|
@@ -21,26 +21,26 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
<div>
|
|
23
23
|
<dt class="text-sm font-medium text-gray-500">Retry Count</dt>
|
|
24
|
-
<dd class="text-sm text-gray-900"><%= @job["retry_count"] %></dd>
|
|
24
|
+
<dd class="text-sm text-gray-900 dark:text-white"><%= @job["retry_count"] %></dd>
|
|
25
25
|
</div>
|
|
26
26
|
</dl>
|
|
27
27
|
</div>
|
|
28
28
|
|
|
29
|
-
<div class="rounded-lg bg-white shadow ring-1 ring-gray-200 p-6 mb-6">
|
|
29
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700 p-6 mb-6">
|
|
30
30
|
<h2 class="text-sm font-medium text-gray-500 mb-2">Error Message</h2>
|
|
31
31
|
<p class="text-sm text-red-700"><%= @job["error_message"] %></p>
|
|
32
32
|
</div>
|
|
33
33
|
|
|
34
34
|
<% if @job["backtrace"].present? %>
|
|
35
|
-
<div class="rounded-lg bg-white shadow ring-1 ring-gray-200 p-6 mb-6">
|
|
35
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700 p-6 mb-6">
|
|
36
36
|
<h2 class="text-sm font-medium text-gray-500 mb-2">Backtrace</h2>
|
|
37
|
-
<pre class="text-xs text-gray-600 bg-gray-50 rounded p-4 overflow-x-auto max-h-96"><%= @job["backtrace"] %></pre>
|
|
37
|
+
<pre class="text-xs text-gray-600 bg-gray-50 dark:bg-gray-900 rounded p-4 overflow-x-auto max-h-96"><%= @job["backtrace"] %></pre>
|
|
38
38
|
</div>
|
|
39
39
|
<% end %>
|
|
40
40
|
|
|
41
|
-
<div class="rounded-lg bg-white shadow ring-1 ring-gray-200 p-6 mb-6">
|
|
41
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700 p-6 mb-6">
|
|
42
42
|
<h2 class="text-sm font-medium text-gray-500 mb-2">Payload</h2>
|
|
43
|
-
<pre class="text-xs text-gray-600 bg-gray-50 rounded p-4 overflow-x-auto"><%= JSON.pretty_generate(JSON.parse(@job["payload"])) rescue @job["payload"] %></pre>
|
|
43
|
+
<pre class="text-xs text-gray-600 bg-gray-50 dark:bg-gray-900 rounded p-4 overflow-x-auto"><%= JSON.pretty_generate(JSON.parse(@job["payload"])) rescue @job["payload"] %></pre>
|
|
44
44
|
</div>
|
|
45
45
|
|
|
46
46
|
<div class="flex space-x-2">
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
<div class="mb-6">
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Job Locks</h1>
|
|
3
|
+
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Active uniqueness locks preventing duplicate job execution</p>
|
|
4
|
+
</div>
|
|
5
|
+
|
|
6
|
+
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
7
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
8
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
9
|
+
<tr>
|
|
10
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500 dark:text-gray-400">Lock Key</th>
|
|
11
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500 dark:text-gray-400">Job Class</th>
|
|
12
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500 dark:text-gray-400">State</th>
|
|
13
|
+
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500 dark:text-gray-400">Owner</th>
|
|
14
|
+
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500 dark:text-gray-400">Age</th>
|
|
15
|
+
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500 dark:text-gray-400">Expires</th>
|
|
16
|
+
</tr>
|
|
17
|
+
</thead>
|
|
18
|
+
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
19
|
+
<% @locks.each do |lock| %>
|
|
20
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50">
|
|
21
|
+
<td class="px-4 py-3 text-sm font-mono text-gray-700 dark:text-gray-300 max-w-xs truncate"><%= lock[:lock_key] %></td>
|
|
22
|
+
<td class="px-4 py-3 text-sm text-gray-700 dark:text-gray-300"><%= lock[:job_class] %></td>
|
|
23
|
+
<td class="px-4 py-3 text-sm">
|
|
24
|
+
<% if lock[:state] == "executing" %>
|
|
25
|
+
<span class="inline-flex items-center rounded-full bg-blue-100 dark:bg-blue-900/50 px-2.5 py-0.5 text-xs font-medium text-blue-800 dark:text-blue-300">Executing</span>
|
|
26
|
+
<% else %>
|
|
27
|
+
<span class="inline-flex items-center rounded-full bg-yellow-100 dark:bg-yellow-900/50 px-2.5 py-0.5 text-xs font-medium text-yellow-800 dark:text-yellow-300">Queued</span>
|
|
28
|
+
<% end %>
|
|
29
|
+
</td>
|
|
30
|
+
<td class="px-4 py-3 text-sm text-gray-500 dark:text-gray-400">
|
|
31
|
+
<% if lock[:owner_pid] %>
|
|
32
|
+
<span class="font-mono"><%= lock[:owner_pid] %></span>
|
|
33
|
+
<% if lock[:owner_hostname] %>
|
|
34
|
+
<span class="text-xs text-gray-400 dark:text-gray-500">@<%= lock[:owner_hostname] %></span>
|
|
35
|
+
<% end %>
|
|
36
|
+
<% else %>
|
|
37
|
+
<span class="text-gray-400 dark:text-gray-500">—</span>
|
|
38
|
+
<% end %>
|
|
39
|
+
</td>
|
|
40
|
+
<td class="px-4 py-3 text-sm text-right text-gray-500 dark:text-gray-400">
|
|
41
|
+
<% if lock[:age_seconds] %>
|
|
42
|
+
<%= pgbus_duration(lock[:age_seconds]) %>
|
|
43
|
+
<% end %>
|
|
44
|
+
</td>
|
|
45
|
+
<td class="px-4 py-3 text-sm text-right text-gray-500 dark:text-gray-400"><%= pgbus_time_ago_future(lock[:expires_at]) %></td>
|
|
46
|
+
</tr>
|
|
47
|
+
<% end %>
|
|
48
|
+
<% if @locks.empty? %>
|
|
49
|
+
<tr><td colspan="6" class="px-4 py-8 text-center text-sm text-gray-400 dark:text-gray-500">No active locks</td></tr>
|
|
50
|
+
<% end %>
|
|
51
|
+
</tbody>
|
|
52
|
+
</table>
|
|
53
|
+
</div>
|
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
<div class="mb-6">
|
|
2
|
-
<h1 class="text-2xl font-bold text-gray-900">Outbox</h1>
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Outbox</h1>
|
|
3
3
|
<p class="mt-1 text-sm text-gray-500">Transactional outbox entries pending publication to PGMQ</p>
|
|
4
4
|
</div>
|
|
5
5
|
|
|
6
6
|
<div class="mb-6 grid grid-cols-3 gap-4">
|
|
7
|
-
<div class="rounded-lg bg-white p-4 shadow ring-1 ring-gray-200">
|
|
7
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 p-4 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
8
8
|
<dt class="text-xs font-medium uppercase text-gray-500">Unpublished</dt>
|
|
9
|
-
<dd class="mt-1 text-2xl font-semibold text-gray-900"><%= pgbus_number(@stats[:unpublished]) %></dd>
|
|
9
|
+
<dd class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white"><%= pgbus_number(@stats[:unpublished]) %></dd>
|
|
10
10
|
</div>
|
|
11
|
-
<div class="rounded-lg bg-white p-4 shadow ring-1 ring-gray-200">
|
|
11
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 p-4 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
12
12
|
<dt class="text-xs font-medium uppercase text-gray-500">Total</dt>
|
|
13
|
-
<dd class="mt-1 text-2xl font-semibold text-gray-900"><%= pgbus_number(@stats[:total]) %></dd>
|
|
13
|
+
<dd class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white"><%= pgbus_number(@stats[:total]) %></dd>
|
|
14
14
|
</div>
|
|
15
|
-
<div class="rounded-lg bg-white p-4 shadow ring-1 ring-gray-200">
|
|
15
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 p-4 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
16
16
|
<dt class="text-xs font-medium uppercase text-gray-500">Oldest Unpublished</dt>
|
|
17
|
-
<dd class="mt-1 text-2xl font-semibold text-gray-900"><%= @stats[:oldest_unpublished_age] ? "#{@stats[:oldest_unpublished_age]}s" : "—" %></dd>
|
|
17
|
+
<dd class="mt-1 text-2xl font-semibold text-gray-900 dark:text-white"><%= @stats[:oldest_unpublished_age] ? "#{@stats[:oldest_unpublished_age]}s" : "—" %></dd>
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
|
-
<div class="overflow-hidden rounded-lg bg-white shadow ring-1 ring-gray-200">
|
|
22
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
23
|
-
<thead class="bg-gray-50">
|
|
21
|
+
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
22
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
23
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
24
24
|
<tr>
|
|
25
25
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">ID</th>
|
|
26
26
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Queue / Topic</th>
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500">Created</th>
|
|
31
31
|
</tr>
|
|
32
32
|
</thead>
|
|
33
|
-
<tbody class="divide-y divide-gray-100">
|
|
33
|
+
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
34
34
|
<% @entries.each do |entry| %>
|
|
35
|
-
<tr class="hover:bg-gray-50">
|
|
35
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
36
36
|
<td class="px-4 py-3 text-sm font-mono text-gray-700"><%= entry.id %></td>
|
|
37
37
|
<td class="px-4 py-3 text-sm text-gray-700"><%= entry.routing_key || entry.queue_name %></td>
|
|
38
38
|
<td class="px-4 py-3 text-sm text-gray-500 max-w-xs truncate"><%= pgbus_json_preview(entry.payload) %></td>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<turbo-frame id="processes-list" data-auto-refresh src="<%= pgbus.processes_path(frame: 'list') %>">
|
|
2
|
-
<div class="overflow-hidden rounded-lg bg-white shadow ring-1 ring-gray-200">
|
|
3
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
4
|
-
<thead class="bg-gray-50">
|
|
2
|
+
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
3
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
4
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
5
5
|
<tr>
|
|
6
6
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Kind</th>
|
|
7
7
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Hostname</th>
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Metadata</th>
|
|
12
12
|
</tr>
|
|
13
13
|
</thead>
|
|
14
|
-
<tbody class="divide-y divide-gray-100">
|
|
14
|
+
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
15
15
|
<% @processes.each do |p| %>
|
|
16
|
-
<tr class="hover:bg-gray-50">
|
|
17
|
-
<td class="px-4 py-3 text-sm font-medium text-gray-900"><%= p[:kind] %></td>
|
|
16
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
17
|
+
<td class="px-4 py-3 text-sm font-medium text-gray-900 dark:text-white"><%= p[:kind] %></td>
|
|
18
18
|
<td class="px-4 py-3 text-sm text-gray-700"><%= p[:hostname] %></td>
|
|
19
19
|
<td class="px-4 py-3 text-sm font-mono text-gray-700"><%= p[:pid] %></td>
|
|
20
20
|
<td class="px-4 py-3 text-sm"><%= pgbus_status_badge(p[:healthy]) %></td>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<turbo-frame id="queues-list" data-auto-refresh src="<%= pgbus.queues_path(frame: 'list') %>">
|
|
2
|
-
<div class="overflow-hidden rounded-lg bg-white shadow ring-1 ring-gray-200">
|
|
3
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
4
|
-
<thead class="bg-gray-50">
|
|
2
|
+
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
3
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
4
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
5
5
|
<tr>
|
|
6
6
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Queue</th>
|
|
7
7
|
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500">Depth</th>
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
<th class="px-4 py-3 text-right text-xs font-medium uppercase text-gray-500">Actions</th>
|
|
13
13
|
</tr>
|
|
14
14
|
</thead>
|
|
15
|
-
<tbody class="divide-y divide-gray-100">
|
|
15
|
+
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
16
16
|
<% @queues.each do |q| %>
|
|
17
|
-
<tr class="hover:bg-gray-50">
|
|
17
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
18
18
|
<td class="px-4 py-3 text-sm">
|
|
19
19
|
<%= link_to q[:name], pgbus.queue_path(name: q[:name]), class: "font-medium text-indigo-600 hover:text-indigo-500", data: { turbo_frame: "_top" } %>
|
|
20
20
|
<%= pgbus_queue_badge(q[:name]) %>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<div class="flex items-center justify-between mb-6">
|
|
2
2
|
<div>
|
|
3
|
-
<h1 class="text-2xl font-bold text-gray-900"><%= @queue&.dig(:name) || params[:name] %></h1>
|
|
3
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white"><%= @queue&.dig(:name) || params[:name] %></h1>
|
|
4
4
|
<% if @queue %>
|
|
5
5
|
<p class="text-sm text-gray-500 mt-1">
|
|
6
6
|
Depth: <span class="font-mono"><%= @queue[:queue_length] %></span> |
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
</div>
|
|
19
19
|
|
|
20
20
|
<!-- Messages in Queue -->
|
|
21
|
-
<div class="overflow-hidden rounded-lg bg-white shadow ring-1 ring-gray-200">
|
|
22
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
23
|
-
<thead class="bg-gray-50">
|
|
21
|
+
<div class="overflow-hidden rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
22
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
23
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
24
24
|
<tr>
|
|
25
25
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">ID</th>
|
|
26
26
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Enqueued</th>
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
<th class="px-4 py-3 text-left text-xs font-medium uppercase text-gray-500">Payload</th>
|
|
30
30
|
</tr>
|
|
31
31
|
</thead>
|
|
32
|
-
<tbody class="divide-y divide-gray-100">
|
|
32
|
+
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
|
|
33
33
|
<% @messages.each do |m| %>
|
|
34
|
-
<tr class="hover:bg-gray-50">
|
|
35
|
-
<td class="px-4 py-3 text-sm font-mono text-gray-900"><%= m[:msg_id] %></td>
|
|
34
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
35
|
+
<td class="px-4 py-3 text-sm font-mono text-gray-900 dark:text-white"><%= m[:msg_id] %></td>
|
|
36
36
|
<td class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(m[:enqueued_at]) %></td>
|
|
37
37
|
<td class="px-4 py-3 text-sm text-gray-500"><%= m[:read_ct] %></td>
|
|
38
38
|
<td class="px-4 py-3 text-sm text-gray-500"><%= pgbus_time_ago(m[:vt]) %></td>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<turbo-frame id="recurring-tasks" data-auto-refresh src="<%= pgbus.recurring_tasks_path(frame: 'recurring_tasks') %>">
|
|
2
|
-
<div class="rounded-lg bg-white shadow ring-1 ring-gray-200">
|
|
2
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
3
3
|
<% if @recurring_tasks.empty? %>
|
|
4
4
|
<div class="p-8 text-center text-gray-500">
|
|
5
5
|
<p class="text-lg font-medium">No recurring tasks configured</p>
|
|
6
6
|
<p class="mt-1 text-sm">Add tasks to <code class="bg-gray-100 px-1.5 py-0.5 rounded text-xs">config/recurring.yml</code></p>
|
|
7
7
|
</div>
|
|
8
8
|
<% else %>
|
|
9
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
10
|
-
<thead class="bg-gray-50">
|
|
9
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
10
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
11
11
|
<tr>
|
|
12
12
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Task</th>
|
|
13
13
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Schedule</th>
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
<th class="px-4 py-3 text-right text-xs font-medium text-gray-500 uppercase">Actions</th>
|
|
19
19
|
</tr>
|
|
20
20
|
</thead>
|
|
21
|
-
<tbody class="divide-y divide-gray-200">
|
|
21
|
+
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
|
|
22
22
|
<% @recurring_tasks.each do |task| %>
|
|
23
|
-
<tr class="hover:bg-gray-50">
|
|
23
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
24
24
|
<td class="px-4 py-3">
|
|
25
25
|
<div>
|
|
26
26
|
<%= link_to task[:key], pgbus.recurring_task_path(task[:id]),
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<% end %>
|
|
33
33
|
</td>
|
|
34
34
|
<td class="px-4 py-3">
|
|
35
|
-
<div class="text-sm text-gray-900"><%= task[:schedule] %></div>
|
|
35
|
+
<div class="text-sm text-gray-900 dark:text-white"><%= task[:schedule] %></div>
|
|
36
36
|
<% if task[:human_schedule] && task[:human_schedule] != task[:schedule] %>
|
|
37
37
|
<div class="text-xs text-gray-400"><%= task[:human_schedule] %></div>
|
|
38
38
|
<% end %>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<div class="flex items-center justify-between mb-6">
|
|
2
|
-
<h1 class="text-2xl font-bold text-gray-900">Recurring Tasks</h1>
|
|
2
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">Recurring Tasks</h1>
|
|
3
3
|
<span class="text-sm text-gray-500"><%= @recurring_tasks.size %> task(s) configured</span>
|
|
4
4
|
</div>
|
|
5
5
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<div class="mb-6">
|
|
2
2
|
<div class="flex items-center justify-between">
|
|
3
3
|
<div>
|
|
4
|
-
<h1 class="text-2xl font-bold text-gray-900"><%= @task[:key] %></h1>
|
|
4
|
+
<h1 class="text-2xl font-bold text-gray-900 dark:text-white"><%= @task[:key] %></h1>
|
|
5
5
|
<p class="mt-1 text-sm text-gray-500"><%= @task[:class_name] || @task[:command] %></p>
|
|
6
6
|
</div>
|
|
7
7
|
<div class="flex space-x-2">
|
|
@@ -21,90 +21,90 @@
|
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
23
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-8">
|
|
24
|
-
<div class="rounded-lg bg-white p-5 shadow ring-1 ring-gray-200">
|
|
24
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
25
25
|
<p class="text-sm font-medium text-gray-500">Schedule</p>
|
|
26
|
-
<p class="mt-1 text-lg font-semibold text-gray-900"><%= @task[:schedule] %></p>
|
|
26
|
+
<p class="mt-1 text-lg font-semibold text-gray-900 dark:text-white"><%= @task[:schedule] %></p>
|
|
27
27
|
<% if @task[:human_schedule] && @task[:human_schedule] != @task[:schedule] %>
|
|
28
28
|
<p class="text-xs text-gray-400"><%= @task[:human_schedule] %></p>
|
|
29
29
|
<% end %>
|
|
30
30
|
</div>
|
|
31
31
|
|
|
32
|
-
<div class="rounded-lg bg-white p-5 shadow ring-1 ring-gray-200">
|
|
32
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
33
33
|
<p class="text-sm font-medium text-gray-500">Next Run</p>
|
|
34
34
|
<% if @task[:enabled] && @task[:next_run_at] %>
|
|
35
|
-
<p class="mt-1 text-lg font-semibold text-gray-900"><%= pgbus_time_ago_future(@task[:next_run_at]) %></p>
|
|
35
|
+
<p class="mt-1 text-lg font-semibold text-gray-900 dark:text-white"><%= pgbus_time_ago_future(@task[:next_run_at]) %></p>
|
|
36
36
|
<p class="text-xs text-gray-400"><%= @task[:next_run_at]&.strftime("%Y-%m-%d %H:%M:%S %Z") %></p>
|
|
37
37
|
<% else %>
|
|
38
38
|
<p class="mt-1 text-lg font-semibold text-gray-400">—</p>
|
|
39
39
|
<% end %>
|
|
40
40
|
</div>
|
|
41
41
|
|
|
42
|
-
<div class="rounded-lg bg-white p-5 shadow ring-1 ring-gray-200">
|
|
42
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 p-5 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
43
43
|
<p class="text-sm font-medium text-gray-500">Status</p>
|
|
44
44
|
<p class="mt-1"><%= @task[:enabled] ? pgbus_recurring_health_badge(@task) : raw('<span class="inline-flex items-center rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium text-gray-600">Disabled</span>') %></p>
|
|
45
45
|
</div>
|
|
46
46
|
</div>
|
|
47
47
|
|
|
48
|
-
<div class="rounded-lg bg-white shadow ring-1 ring-gray-200 mb-8">
|
|
48
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700 mb-8">
|
|
49
49
|
<div class="px-4 py-3 border-b border-gray-200">
|
|
50
|
-
<h2 class="text-lg font-medium text-gray-900">Configuration</h2>
|
|
50
|
+
<h2 class="text-lg font-medium text-gray-900 dark:text-white">Configuration</h2>
|
|
51
51
|
</div>
|
|
52
52
|
<div class="p-4">
|
|
53
53
|
<dl class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
54
54
|
<div>
|
|
55
55
|
<dt class="text-sm font-medium text-gray-500">Job Class</dt>
|
|
56
|
-
<dd class="mt-1 text-sm text-gray-900"><%= @task[:class_name] || "—" %></dd>
|
|
56
|
+
<dd class="mt-1 text-sm text-gray-900 dark:text-white"><%= @task[:class_name] || "—" %></dd>
|
|
57
57
|
</div>
|
|
58
58
|
<% if @task[:command] %>
|
|
59
59
|
<div>
|
|
60
60
|
<dt class="text-sm font-medium text-gray-500">Command</dt>
|
|
61
|
-
<dd class="mt-1 text-sm text-gray-900 font-mono text-xs"><%= @task[:command] %></dd>
|
|
61
|
+
<dd class="mt-1 text-sm text-gray-900 dark:text-white font-mono text-xs"><%= @task[:command] %></dd>
|
|
62
62
|
</div>
|
|
63
63
|
<% end %>
|
|
64
64
|
<div>
|
|
65
65
|
<dt class="text-sm font-medium text-gray-500">Queue</dt>
|
|
66
|
-
<dd class="mt-1 text-sm text-gray-900"><%= @task[:queue_name] || "default" %></dd>
|
|
66
|
+
<dd class="mt-1 text-sm text-gray-900 dark:text-white"><%= @task[:queue_name] || "default" %></dd>
|
|
67
67
|
</div>
|
|
68
68
|
<div>
|
|
69
69
|
<dt class="text-sm font-medium text-gray-500">Priority</dt>
|
|
70
|
-
<dd class="mt-1 text-sm text-gray-900"><%= @task[:priority] %></dd>
|
|
70
|
+
<dd class="mt-1 text-sm text-gray-900 dark:text-white"><%= @task[:priority] %></dd>
|
|
71
71
|
</div>
|
|
72
72
|
<% if @task[:arguments]&.any? %>
|
|
73
73
|
<div class="sm:col-span-2">
|
|
74
74
|
<dt class="text-sm font-medium text-gray-500">Arguments</dt>
|
|
75
|
-
<dd class="mt-1 text-sm text-gray-900 font-mono text-xs"><%= @task[:arguments].inspect %></dd>
|
|
75
|
+
<dd class="mt-1 text-sm text-gray-900 dark:text-white font-mono text-xs"><%= @task[:arguments].inspect %></dd>
|
|
76
76
|
</div>
|
|
77
77
|
<% end %>
|
|
78
78
|
<% if @task[:description] %>
|
|
79
79
|
<div class="sm:col-span-2">
|
|
80
80
|
<dt class="text-sm font-medium text-gray-500">Description</dt>
|
|
81
|
-
<dd class="mt-1 text-sm text-gray-900"><%= @task[:description] %></dd>
|
|
81
|
+
<dd class="mt-1 text-sm text-gray-900 dark:text-white"><%= @task[:description] %></dd>
|
|
82
82
|
</div>
|
|
83
83
|
<% end %>
|
|
84
84
|
<div>
|
|
85
85
|
<dt class="text-sm font-medium text-gray-500">Source</dt>
|
|
86
|
-
<dd class="mt-1 text-sm text-gray-900"><%= @task[:static] ? "Config file" : "Dynamic" %></dd>
|
|
86
|
+
<dd class="mt-1 text-sm text-gray-900 dark:text-white"><%= @task[:static] ? "Config file" : "Dynamic" %></dd>
|
|
87
87
|
</div>
|
|
88
88
|
</dl>
|
|
89
89
|
</div>
|
|
90
90
|
</div>
|
|
91
91
|
|
|
92
|
-
<div class="rounded-lg bg-white shadow ring-1 ring-gray-200">
|
|
92
|
+
<div class="rounded-lg bg-white dark:bg-gray-800 shadow ring-1 ring-gray-200 dark:ring-gray-700">
|
|
93
93
|
<div class="px-4 py-3 border-b border-gray-200">
|
|
94
|
-
<h2 class="text-lg font-medium text-gray-900">Recent Executions</h2>
|
|
94
|
+
<h2 class="text-lg font-medium text-gray-900 dark:text-white">Recent Executions</h2>
|
|
95
95
|
</div>
|
|
96
96
|
<% if @task[:executions]&.any? %>
|
|
97
|
-
<table class="min-w-full divide-y divide-gray-200">
|
|
98
|
-
<thead class="bg-gray-50">
|
|
97
|
+
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
|
98
|
+
<thead class="bg-gray-50 dark:bg-gray-900">
|
|
99
99
|
<tr>
|
|
100
100
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Scheduled For</th>
|
|
101
101
|
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase">Enqueued At</th>
|
|
102
102
|
</tr>
|
|
103
103
|
</thead>
|
|
104
|
-
<tbody class="divide-y divide-gray-200">
|
|
104
|
+
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
|
|
105
105
|
<% @task[:executions].each do |exec| %>
|
|
106
|
-
<tr class="hover:bg-gray-50">
|
|
107
|
-
<td class="px-4 py-3 text-sm text-gray-900">
|
|
106
|
+
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700/50 dark:bg-gray-900">
|
|
107
|
+
<td class="px-4 py-3 text-sm text-gray-900 dark:text-white">
|
|
108
108
|
<%= exec[:run_at]&.strftime("%Y-%m-%d %H:%M:%S %Z") %>
|
|
109
109
|
</td>
|
|
110
110
|
<td class="px-4 py-3 text-sm text-gray-600">
|
data/config/routes.rb
CHANGED
|
@@ -49,8 +49,11 @@ Pgbus::Engine.routes.draw do
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
resources :outbox, only: [:index], controller: "outbox"
|
|
52
|
+
resources :locks, only: [:index]
|
|
53
|
+
resource :insights, only: [:show], controller: "insights"
|
|
52
54
|
|
|
53
55
|
namespace :api do
|
|
54
56
|
get :stats, to: "stats#show"
|
|
57
|
+
get :insights, to: "insights#show"
|
|
55
58
|
end
|
|
56
59
|
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/active_record"
|
|
5
|
+
|
|
6
|
+
module Pgbus
|
|
7
|
+
module Generators
|
|
8
|
+
class AddJobLocksGenerator < Rails::Generators::Base
|
|
9
|
+
include ActiveRecord::Generators::Migration
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
desc "Add job locks table for uniqueness guarantees"
|
|
14
|
+
|
|
15
|
+
class_option :database,
|
|
16
|
+
type: :string,
|
|
17
|
+
default: nil,
|
|
18
|
+
desc: "Use a separate database for pgbus tables (e.g. --database=pgbus)"
|
|
19
|
+
|
|
20
|
+
def create_migration_file
|
|
21
|
+
if separate_database?
|
|
22
|
+
migration_template "add_job_locks.rb.erb",
|
|
23
|
+
"db/pgbus_migrate/add_pgbus_job_locks.rb"
|
|
24
|
+
else
|
|
25
|
+
migration_template "add_job_locks.rb.erb",
|
|
26
|
+
"db/migrate/add_pgbus_job_locks.rb"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def display_post_install
|
|
31
|
+
say ""
|
|
32
|
+
say "Pgbus job locks table installed!", :green
|
|
33
|
+
say ""
|
|
34
|
+
say "Next steps:"
|
|
35
|
+
say " 1. Run: rails db:migrate#{":#{options[:database]}" if separate_database?}"
|
|
36
|
+
say " 2. Add `ensures_uniqueness` to your job classes (DSL is auto-included)"
|
|
37
|
+
say " 3. Restart pgbus: bin/pgbus start"
|
|
38
|
+
say ""
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def migration_version
|
|
44
|
+
"[#{ActiveRecord::Migration.current_version}]"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def separate_database?
|
|
48
|
+
options[:database].present?
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|