diff --git a/.gitignore b/.gitignore index 652dfc513a..5f06417990 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /cache/ /config/*.deployed /config/aliases +/config/cable.yml /config/config.tmp /config/crontab /config/database.yml diff --git a/Gemfile b/Gemfile index 80779b2ae2..b0de8d94d3 100644 --- a/Gemfile +++ b/Gemfile @@ -117,7 +117,6 @@ gem 'matrix', '~> 0.4.2' gem 'mini_magick', '~> 4.13.1' gem 'net-protocol', '~> 0.1.3' gem 'redcarpet', '~> 3.6.0' -gem 'redis', '~> 4.8.1' gem 'rolify', '~> 6.0.1' gem 'ruby-msg', '~> 1.5.0', git: 'https://github.com/mysociety/ruby-msg.git', branch: 'ascii-encoding' gem 'rubyzip', '~> 2.3.2' diff --git a/Gemfile.lock b/Gemfile.lock index 164980537f..9ef78f5a0f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -649,7 +649,6 @@ DEPENDENCIES rails-i18n (~> 7.0.5) recaptcha (~> 5.17.0) redcarpet (~> 3.6.0) - redis (~> 4.8.1) rolify (~> 6.0.1) rspec-activemodel-mocks (~> 1.2.1) rspec-rails (~> 7.0.1) diff --git a/app/channels/application_cable/channel.rb b/app/channels/application_cable/channel.rb new file mode 100644 index 0000000000..d672697283 --- /dev/null +++ b/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb new file mode 100644 index 0000000000..0ff5442f47 --- /dev/null +++ b/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/app/channels/job_status_channel.rb b/app/channels/job_status_channel.rb new file mode 100644 index 0000000000..305d421c67 --- /dev/null +++ b/app/channels/job_status_channel.rb @@ -0,0 +1,5 @@ +class JobStatusChannel < ApplicationCable::Channel + def subscribed + stream_from 'job_status_channel' + end +end diff --git a/app/controllers/jobs_controller.rb b/app/controllers/jobs_controller.rb new file mode 100644 index 0000000000..4828f9cb24 --- /dev/null +++ b/app/controllers/jobs_controller.rb @@ -0,0 +1,9 @@ +class JobsController < ApplicationController + def index + end + + def start + LongRunningJob.perform_later(current_user&.id) + redirect_to jobs_path + end +end diff --git a/app/javascript/channels/consumer.js b/app/javascript/channels/consumer.js new file mode 100644 index 0000000000..940c8adb1a --- /dev/null +++ b/app/javascript/channels/consumer.js @@ -0,0 +1,2 @@ +import { createConsumer } from "@rails/actioncable" +export default createConsumer() diff --git a/app/javascript/channels/index.js b/app/javascript/channels/index.js new file mode 100644 index 0000000000..280d96a668 --- /dev/null +++ b/app/javascript/channels/index.js @@ -0,0 +1,2 @@ +// Import all the channels to be used by Action Cable +import "./job_status_channel" diff --git a/app/javascript/channels/job_status_channel.js b/app/javascript/channels/job_status_channel.js new file mode 100644 index 0000000000..939897a87f --- /dev/null +++ b/app/javascript/channels/job_status_channel.js @@ -0,0 +1,13 @@ +import consumer from "./consumer" + +consumer.subscriptions.create("JobStatusChannel", { + received(data) { + const statusElement = document.getElementById("job-status") + const progressElement = document.getElementById("job-progress") + const resultElement = document.getElementById("job-result") + + if (statusElement) statusElement.textContent = data.status + if (progressElement) progressElement.value = data.progress + if (data.result && resultElement) resultElement.textContent = data.result + } +}) diff --git a/app/javascript/modern_application.js b/app/javascript/modern_application.js index 57c70c4406..d8dd2e61f9 100644 --- a/app/javascript/modern_application.js +++ b/app/javascript/modern_application.js @@ -1,5 +1,6 @@ // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails import "@hotwired/turbo-rails"; +import "channels"; import "controllers"; // Disable old jQuery UJS event handling, allowing Turbo to handle instead diff --git a/app/jobs/long_running_job.rb b/app/jobs/long_running_job.rb new file mode 100644 index 0000000000..05d47204ae --- /dev/null +++ b/app/jobs/long_running_job.rb @@ -0,0 +1,30 @@ +class LongRunningJob < ApplicationJob + queue_as :default + + def perform(_user_id) + progress = 0 + + while progress < 99 + sleep(rand(0.5..2.0)) + progress += rand(5..15) + progress = [progress, 99].min + + ActionCable.server.broadcast( + 'job_status_channel', + { + status: 'Processing...', + progress: progress + } + ) + end + + ActionCable.server.broadcast( + 'job_status_channel', + { + status: 'Completed', + progress: 100, + result: "Task completed at #{Time.current}" + } + ) + end +end diff --git a/app/views/jobs/index.html.erb b/app/views/jobs/index.html.erb new file mode 100644 index 0000000000..b370c333d4 --- /dev/null +++ b/app/views/jobs/index.html.erb @@ -0,0 +1,15 @@ +<% content_for :javascript_head do %> + <%= javascript_importmap_tags('modern_application') %> +<% end %> + +
Status: Not started
+ +Result:
+