Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better support API-only Rails applications #1128

Merged
merged 2 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,13 @@ take a look at the [Active Job documentation][active-job-docs].
[async-adapter]: https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/AsyncAdapter.html
[active-job-docs]: https://guides.rubyonrails.org/active_job_basics.html#setting-the-backend

### Action Controller & Action View Dependency

The Maintenance Tasks framework relies on Action Controller and Action View to
render the UI. If you're using Rails in API-only mode, see [Using Maintenance
Tasks in API-only
applications](#using-maintenance-tasks-in-api-only-applications).

### Autoloading

The Maintenance Tasks framework does not support autoloading in `:classic` mode.
Expand Down Expand Up @@ -888,6 +895,42 @@ a Task can be in:
* **succeeded**: A Task that finished successfully.
* **errored**: A Task that encountered an unhandled exception while performing.

### Using Maintenance Tasks in API-only applications

The Maintenance Tasks engine uses Rails sessions for flash messages and storing
the CSRF token. For the engine to work in an API-only Rails application, you
need to add a [session middleware][] and the `ActionDispatch::Flash`
middleware. The engine also defines a strict [Content Security Policy][], make
sure to include `ActionDispatch::ContentSecurityPolicy::Middleware` in your
app's middleware stack to ensure the CSP is delivered to the user's browser.

[session middleware]: https://guides.rubyonrails.org/api_app.html#using-session-middlewares
[Content Security Policy]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP

Configuring Rails applications is beyond the scope of this documentation, but
one way to do this is to add these lines to your application configuration:

```ruby
# config/application.rb
module YourApplication
class Application < Rails::Application
# ...
config.api_only = true

config.middleware.insert_before ::Rack::Head, ::ActionDispatch::Flash
config.middleware.insert_before ::Rack::Head, ::ActionDispatch::ContentSecurityPolicy::Middleware
config.session_store :cookie_store, key: "_#{railtie_name.chomp("_application")}_session", secure: true
config.middleware.insert_before ::ActionDispatch::Flash, config.session_store, config.session_options
config.middleware.insert_before config.session_store, ActionDispatch::Cookies
end
end
```

You can read more in the [Using Rails for API-only Applications][rails api] Rails
guide.

[rails api]: https://guides.rubyonrails.org/api_app.html

### How Maintenance Tasks runs a Task

Maintenance tasks can be running for a long time, and the purpose of the gem is
Expand Down Expand Up @@ -1145,7 +1188,7 @@ The value for `MaintenanceTasks.stuck_task_duration` must be an
`ActiveSupport::Duration`. If no value is specified, it will default to 5
minutes.

### Metadata
#### Metadata

`MaintenanceTasks.metadata` can be configured to specify a proc from which to
get extra information about the run. Since this proc will be ran in the context
Expand Down
18 changes: 9 additions & 9 deletions app/views/maintenance_tasks/runs/_run.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,23 @@

<div class="buttons">
<% if run.paused? %>
<%= button_to 'Resume', resume_task_run_path(@task, run), method: :put, class: 'button is-primary', disabled: @task.deleted? %>
<%= button_to 'Cancel', cancel_task_run_path(@task, run), method: :put, class: 'button is-danger' %>
<%= button_to 'Resume', resume_task_run_path(@task, run), class: 'button is-primary', disabled: @task.deleted? %>
<%= button_to 'Cancel', cancel_task_run_path(@task, run), class: 'button is-danger' %>
<% elsif run.errored? %>
<%= button_to 'Resume', resume_task_run_path(@task, run), method: :put, class: 'button is-primary', disabled: @task.deleted? %>
<%= button_to 'Resume', resume_task_run_path(@task, run), class: 'button is-primary', disabled: @task.deleted? %>
<% elsif run.cancelling? %>
<% if run.stuck? %>
<%= button_to 'Cancel', cancel_task_run_path(@task, run), method: :put, class: 'button is-danger', disabled: @task.deleted? %>
<%= button_to 'Cancel', cancel_task_run_path(@task, run), class: 'button is-danger', disabled: @task.deleted? %>
<% end %>
<% elsif run.pausing? %>
<%= button_to 'Pausing', pause_task_run_path(@task, run), method: :put, class: 'button is-warning', disabled: true %>
<%= button_to 'Cancel', cancel_task_run_path(@task, run), method: :put, class: 'button is-danger' %>
<%= button_to 'Pausing', pause_task_run_path(@task, run), class: 'button is-warning', disabled: true %>
<%= button_to 'Cancel', cancel_task_run_path(@task, run), class: 'button is-danger' %>
<% if run.stuck? %>
<%= button_to 'Force pause', pause_task_run_path(@task, run), method: :put, class: 'button is-danger', disabled: @task.deleted? %>
<%= button_to 'Force pause', pause_task_run_path(@task, run), class: 'button is-danger', disabled: @task.deleted? %>
<% end %>
<% elsif run.active? %>
<%= button_to 'Pause', pause_task_run_path(@task, run), method: :put, class: 'button is-warning', disabled: @task.deleted? %>
<%= button_to 'Cancel', cancel_task_run_path(@task, run), method: :put, class: 'button is-danger' %>
<%= button_to 'Pause', pause_task_run_path(@task, run), class: 'button is-warning', disabled: @task.deleted? %>
<%= button_to 'Cancel', cancel_task_run_path(@task, run), class: 'button is-danger' %>
<% end%>
</div>
</div>
6 changes: 3 additions & 3 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
resources :tasks, only: [:index, :show], format: false do
resources :runs, only: [:create], format: false do
member do
put "pause"
put "cancel"
put "resume"
post "pause"
post "cancel"
post "resume"
end
end
get :runs, to: redirect("tasks/%{task_id}")
Expand Down