Tag: active_admin

  • I’ve been using both Active Admin and Delayed::Job for years now and both have served me very well. It’s very common for me to want to display job records in the admin tool and have some extra tools around them such as:

    • the ability to mark them all for re-run
    • the ability to run one manually (not recommended for production)
    • the ability to run them all manually (also not recommended for production)
    • an easy way to delete them all
    • a good view of the data inside the job

    To achieve this, over the years, my admin/delayed_job.rb grew and I took it from project to project. Today I want to share it with you in case you are doing the same:

    ActiveAdmin.register Delayed::Job, as: "DelayedJob" do
      collection_action :run_all, method: :post do
        successes, failures = Delayed::Worker.new.work_off
        if failures > 0
          flash[:alert] = "#{failures} failed delayed jobs when running them."
        end
        if successes > 0
          flash[:notice] = "#{successes} delayed jobs run successfully"
        end
        if failures == 0 && successes == 0
          flash[:notice] = "Yawn... no delayed jobs run"
        end
        redirect_to admin_delayed_jobs_url
        I18n.locale = :en # Running delayed jobs can mess up the locale.
      end
    
      if Rails.env.development?
        collection_action :delete_all, method: :post do
          n = Delayed::Job.delete_all
          redirect_to admin_delayed_jobs_url, notice: "#{n} jobs deleted."
        end
      end
    
      collection_action :mark_all_for_re_run, method: :post do
        n = Delayed::Job.update_all("run_at = created_at")
        redirect_to admin_delayed_jobs_url, notice: "Marked all jobs (#{n}) for re-running."
      end
    
      member_action :run, method: :post do
        delayed_job = Delayed::Job.find(params[:id])
        begin
          delayed_job.invoke_job
          delayed_job.destroy
          redirect_to admin_delayed_jobs_url, notice: "1 delayed job run, apparently successfully, but who knows!"
        rescue => e
          redirect_to admin_delayed_jobs_url, alert: "Failed to run a delayed job: #{e.to_s}"
        end
        I18n.locale = :en # Running delayed jobs can mess up the locale.
      end
    
      action_item do
        links = link_to("Run All Delayed Jobs", run_all_admin_delayed_jobs_url, method: :post)
        links += (" " + link_to("Mark all for re-run", mark_all_for_re_run_admin_delayed_jobs_url, method: :post)).html_safe
        links += (" " + link_to("Delete All Delayed Jobs", delete_all_admin_delayed_jobs_url, method: :post)).html_safe if Rails.env.development?
        links
      end
    
      index do
        selectable_column
        id_column
        column "P", :priority
        column "A", :attempts
        column("Error", :last_error, sortable: :last_error) { |post| post.last_error.present? ? post.last_error.split("\n").first : "" }
        column(:created_at, sortable: :created_at) { |job| job.created_at.iso8601.gsub("T", " ") }
        column(:run_at, sortable: :run_at) { |post| post.run_at.present? ? post.run_at.iso8601.gsub("T", " ") : nil }
        column :queue
        column("Running", sortable: :locked_at) { |dj| dj.locked_at.present? ? "#{(Time.now - dj.locked_at).round(1)}s by #{dj.locked_by}" : "" }
        actions
      end
    
      show title: ->(dj) { "Delayed job #{dj.id}" } do |delayed_job|
        panel "Delayed job" do
          attributes_table_for delayed_job do
            row :id
            row :priority
            row :attempts
            row :queue
            row :run_at
            row :locked_at
            row :failed_at
            row :locked_by
            row :created_at
            row :updated_at
          end
        end
    
        panel "Handler" do
          begin
            pre delayed_job.handler
          rescue => e
            div "Couldn't render handler: #{e.message}"
          end
        end
    
        panel "Last error" do
          begin
            pre delayed_job.last_error
          rescue => e
            div "Couldn't render last error: #{e.message}"
          end
        end
    
        active_admin_comments
      end
    
      form do |f|
        f.inputs("Delayed job") do
          f.input :id, input_html: { readonly: true }
          f.input :priority
          f.input :attempts
          f.input :queue
          f.input :created_at, input_html: { readonly: true }, as: :string
          f.input :updated_at, input_html: { readonly: true }, as: :string
          f.input :run_at, input_html: { readonly: true }, as: :string
          f.input :locked_at, input_html: { readonly: true }, as: :string
          f.input :failed_at, input_html: { readonly: true }, as: :string
          f.input :locked_by, input_html: { readonly: true }
        end
    
        f.buttons
      end
    
      controller do
        def update
          @delayed_job = Delayed::Job.find(params[:id])
          @delayed_job.assign_attributes(params[:delayed_job], without_protection: true)
          if @delayed_job.save
            redirect_to admin_delayed_jobs_url, notice: "Delayed job #{@delayed_job} saved successfully"
          else
            render :edit
          end
          I18n.locale = :en # Running delayed jobs can mess up the locale.
        end
      end
    end