Class: ChronoForge::Dashboard::ActionsController
- Inherits:
-
BaseController
- Object
- ActionController::Base
- BaseController
- ChronoForge::Dashboard::ActionsController
- Defined in:
- app/controllers/chrono_forge/dashboard/actions_controller.rb
Instance Method Summary collapse
-
#bulk_reap ⇒ Object
Reap every stranded workflow (running with a stale lock) in the background — the bulk form of #reap, delegating to Workflow.reap_stalled.
-
#bulk_retry ⇒ Object
Retry every blocked (failed/stalled) workflow.
-
#bulk_retry_branch ⇒ Object
Retry every blocked (failed/stalled) child of one branch, in the background.
-
#reap ⇒ Object
Recover a workflow stranded in :running — the single-workflow form of the stalled-workflow reaper (Workflow.reap_stalled).
-
#resume ⇒ Object
Re-enqueue an idle (parked) workflow so the executor picks it up again.
- #retry ⇒ Object
- #unlock ⇒ Object
Instance Method Details
#bulk_reap ⇒ Object
Reap every stranded workflow (running with a stale lock) in the background — the bulk form of #reap, delegating to Workflow.reap_stalled. The count is taken up front for the flash; the job does the sweep.
44 45 46 47 48 49 50 |
# File 'app/controllers/chrono_forge/dashboard/actions_controller.rb', line 44 def bulk_reap cutoff = ChronoForge.config.reap_stale_after.ago n = ChronoForge::Workflow.where(state: ChronoForge::Workflow.states[:running]).where(locked_at: ...cutoff).count return redirect_to(stranded_index_path, notice: "No stranded workflows to reap.", status: :see_other) if n.zero? BulkReapJob.perform_later redirect_to stranded_index_path, notice: "Reaping #{n} stranded workflow(s) in the background.", status: :see_other end |
#bulk_retry ⇒ Object
Retry every blocked (failed/stalled) workflow. The fan-out runs in a background job so the request returns fast even with a huge backlog; the count is taken up front for the flash (BulkRetryJob does the enqueueing).
55 56 57 58 59 60 |
# File 'app/controllers/chrono_forge/dashboard/actions_controller.rb', line 55 def bulk_retry n = BulkRetryJob.retryable.count return redirect_to(workflows_path, notice: "No blocked workflows to retry.", status: :see_other) if n.zero? BulkRetryJob.perform_later redirect_to workflows_path, notice: "Retrying #{n} blocked workflow(s) in the background.", status: :see_other end |
#bulk_retry_branch ⇒ Object
Retry every blocked (failed/stalled) child of one branch, in the background.
63 64 65 66 67 68 69 70 71 |
# File 'app/controllers/chrono_forge/dashboard/actions_controller.rb', line 63 def bulk_retry_branch parent = ChronoForge::Workflow.find(params[:workflow_id]) branch_log = parent.execution_logs.find(params[:id]) n = BulkRetryJob.retryable(branch_log).count redirect = ->(msg) { redirect_to workflow_branch_path(parent, branch_log), notice: msg, status: :see_other } return redirect.call("No blocked child workflows to retry.") if n.zero? BulkRetryJob.perform_later(branch_log.id) redirect.call("Retrying #{n} child workflow(s) in the background.") end |
#reap ⇒ Object
Recover a workflow stranded in :running — the single-workflow form of the stalled-workflow reaper (Workflow.reap_stalled). Re-enqueues it so the executor's acquire_lock steals the stale lock and replays completed steps as no-ops. This is the right fix for an overdue/stuck run: unlike Force unlock (which idles the row and leaves nothing to wake it), reap actually re-drives the workflow. Safe and idempotent — a duplicate just loses the acquire_lock race and no-ops.
25 26 27 28 29 |
# File 'app/controllers/chrono_forge/dashboard/actions_controller.rb', line 25 def reap return redirect_to(workflow_path(workflow), alert: "Only running workflows can be reaped.", status: :see_other) unless workflow.running? workflow.job_klass.perform_later(workflow.key, **workflow.kwargs.symbolize_keys) redirect_to workflow_path(workflow), notice: "Reaped #{workflow.key} — re-enqueued to steal its stale lock and replay.", status: :see_other end |
#resume ⇒ Object
Re-enqueue an idle (parked) workflow so the executor picks it up again. This is the recovery for a dropped poll/wake — a wait_until or merge whose poller job was lost, or a continue_if whose event has since arrived: the replay re-checks the condition and re-arms the poll if still unmet.
35 36 37 38 39 |
# File 'app/controllers/chrono_forge/dashboard/actions_controller.rb', line 35 def resume return redirect_to(workflow_path(workflow), alert: "Only idle workflows can be resumed.", status: :see_other) unless workflow.idle? workflow.job_klass.perform_later(workflow.key) redirect_to workflow_path(workflow), notice: "Re-enqueued #{workflow.key}.", status: :see_other end |
#retry ⇒ Object
8 9 10 11 |
# File 'app/controllers/chrono_forge/dashboard/actions_controller.rb', line 8 def retry workflow.retry_later redirect_to workflow_path(workflow), notice: "Re-enqueued #{workflow.key}.", status: :see_other end |
#unlock ⇒ Object
13 14 15 16 |
# File 'app/controllers/chrono_forge/dashboard/actions_controller.rb', line 13 def unlock workflow.update!(locked_at: nil, locked_by: nil, state: :idle) redirect_to workflow_path(workflow), notice: "Unlocked #{workflow.key}.", status: :see_other end |