# Sidekiq Style Guide

> 原文：[https://docs.gitlab.com/ee/development/sidekiq_style_guide.html](https://docs.gitlab.com/ee/development/sidekiq_style_guide.html)

*   [ApplicationWorker](#applicationworker)
*   [Dedicated Queues](#dedicated-queues)
*   [Queue Namespaces](#queue-namespaces)
*   [Idempotent Jobs](#idempotent-jobs)
    *   [Ensuring a worker is idempotent](#ensuring-a-worker-is-idempotent)
    *   [Declaring a worker as idempotent](#declaring-a-worker-as-idempotent)
    *   [Deduplication](#deduplication)
*   [Job urgency](#job-urgency)
    *   [Latency sensitive jobs](#latency-sensitive-jobs)
    *   [Changing a queue’s urgency](#changing-a-queues-urgency)
*   [Jobs with External Dependencies](#jobs-with-external-dependencies)
*   [CPU-bound and Memory-bound Workers](#cpu-bound-and-memory-bound-workers)
*   [Declaring a Job as CPU-bound](#declaring-a-job-as-cpu-bound)
*   [Determining whether a worker is CPU-bound](#determining-whether-a-worker-is-cpu-bound)
*   [Feature category](#feature-category)
*   [Job weights](#job-weights)
*   [Worker context](#worker-context)
    *   [Cron workers](#cron-workers)
    *   [Jobs scheduled in bulk](#jobs-scheduled-in-bulk)
*   [Arguments logging](#arguments-logging)
*   [Tests](#tests)
*   [Sidekiq Compatibility across Updates](#sidekiq-compatibility-across-updates)
    *   [Changing the arguments for a worker](#changing-the-arguments-for-a-worker)
        *   [Remove an argument](#remove-an-argument)
        *   [Add an argument](#add-an-argument)
            *   [Multi-step deployment](#multi-step-deployment)
            *   [Parameter hash](#parameter-hash)
    *   [Removing workers](#removing-workers)
    *   [Renaming queues](#renaming-queues)

# Sidekiq Style Guide[](#sidekiq-style-guide "Permalink")

本文档概述了添加或修改 Sidekiq 工作程序时应遵循的各种准则.

## ApplicationWorker[](#applicationworker "Permalink")

All workers should include `ApplicationWorker` instead of `Sidekiq::Worker`, which adds some convenience methods and automatically sets the queue based on the worker’s name.

## Dedicated Queues[](#dedicated-queues "Permalink")

所有工作程序都应使用自己的队列，该队列将根据工作程序类名称自动设置. 对于名为`ProcessSomethingWorker`的工作程序，队列名称将为`process_something` . 如果不确定工人使用什么队列，可以使用`SomeWorker.queue`找到它. 几乎没有理由使用`sidekiq_options queue: :some_queue`手动覆盖队列名称.

添加新队列后，运行`bin/rake gitlab:sidekiq:all_queues_yml:generate`来重新生成`app/workers/all_queues.yml`或`ee/app/workers/all_queues.yml`以便可以由[`sidekiq-cluster`](../administration/operations/extra_sidekiq_processes.html)拾取.

## Queue Namespaces[](#queue-namespaces "Permalink")

虽然不同的工作人员无法共享队列，但是他们可以共享队列名称空间.

为工作程序定义队列名称空间可以启动 Sidekiq 进程，该进程自动为该工作空间中的所有工作程序处理作业，而无需显式列出其所有队列名称. 例如，如果由`sidekiq-cron`管理的所有工作人员都使用`cronjob`队列名称空间，那么我们可以专门针对此类计划的作业启动 Sidekiq 进程. 如果稍后添加使用`cronjob`命名空间的新工作程序，则 Sidekiq 进程也将自动为该工作程序选择作业（重新启动后），而无需更改任何配置.

可以使用`queue_namespace` DSL 类方法设置队列名称空间：

```
class SomeScheduledTaskWorker
  include ApplicationWorker

  queue_namespace :cronjob

  # ...
end 
```

在后台，这会将`SomeScheduledTaskWorker.queue`设置为`cronjob:some_scheduled_task` . 常用的名称空间将具有自己的关注模块，可以轻松地将其包含在 worker 类中，并且可以设置队列名称空间以外的其他 Sidekiq 选项. 例如， `CronjobQueue`设置名称空间，但也禁用重试.

`bundle exec sidekiq`是可感知名称空间的，当提供名称空间而不是`--queue` （ `-q` ）选项中的简单队列名称时，它将自动侦听名称空间中的所有队列（技术上：所有以名称空间名称为前缀的队列） ，或`config/sidekiq_queues.yml`中的`:queues:`部分.

请注意，应谨慎执行将工作程序添加到现有命名空间的操作，因为如果没有适当调整可用于处理命名空间的 Sidekiq 进程可用的资源，则额外的作业将占用已经存在的工作程序的资源.

## Idempotent Jobs[](#idempotent-jobs "Permalink")

众所周知，一项作业可能由于多种原因而失败. 例如，网络中断或错误. 为了解决此问题，Sidekiq 具有内置的重试机制，GitLab 中的大多数工作人员默认使用该机制.

期望作业在失败后可以再次运行，而不会给应用程序或用户带来重大副作用，这就是 Sidekiq 鼓励作业具有[幂等性和事务性的原因](https://github.com/mperham/sidekiq/wiki/Best-Practices#2-make-your-job-idempotent-and-transactional) .

通常，在以下情况下，可以将工人视为等幂的：

*   它可以使用相同的参数安全地运行多次.
*   预期应用程序副作用仅发生一次（或第二次运行的副作用无效）.

一个很好的例子是缓存过期工作器.

**注意：**如果队列中已经存在具有相同参数的未启动作业，则为等幂工作器调度的作业将自动进行[重复数据删除](#deduplication) .

### Ensuring a worker is idempotent[](#ensuring-a-worker-is-idempotent "Permalink")

确保使用以下共享示例通过工作程序测试：

```
include_examples 'an idempotent worker' do
  it 'marks the MR as merged' do
    # Using subject inside this block will process the job multiple times
    subject

    expect(merge_request.state).to eq('merged')
  end
end 
```

直接使用`perform_multiple`方法而不是`job.perform` （此辅助方法将自动包含在 worker 中）.

### Declaring a worker as idempotent[](#declaring-a-worker-as-idempotent "Permalink")

```
class IdempotentWorker
  include ApplicationWorker

  # Declares a worker is idempotent and can
  # safely run multiple times.
  idempotent!

  # ...
end 
```

鼓励只具有`idempotent!` 即使在另一个类或模块中定义了`perform`方法，也要在最顶层的 worker 类中调用.

**注意：**如果工人阶级没有被标记为幂等，那么警察将失败. 如果您不确定自己的工作可以安全地多次运行，请考虑跳过警察.

### Deduplication[](#deduplication "Permalink")

当队列中有另一个幂函数的作业入队而另一个未启动的作业时，GitLab 会删除第二个作业. 之所以跳过该工作，是因为首先安排的工作将完成相同的工作； 到第二个作业执行时，第一个作业什么也做不了.

例如， `AuthorizedProjectsWorker`需要一个用户 ID. 当工作程序运行时，它将重新计算用户的授权. 每当操作有可能更改用户的授权时，GitLab 都会计划此作业. 如果将同一用户同时添加到两个项目，则如果第一个作业尚未开始，则可以跳过第二个作业，因为当第一个作业运行时，它将为两个项目创建授权.

GitLab 不会跳过将来计划的作业，因为我们假设在计划执行作业时状态将已更改.

[已经提出了](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/195)更多的[重复数据删除策略](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/195) . 如果您正在部署的员工可能会从其他策略中受益，请在问题中发表评论.

如果自动重复数据删除会导致某些队列出现问题. 可以通过启用名为`disable_<queue name>_deduplication`的功能标志来暂时禁用此功能. 例如，要禁用`AuthorizedProjectsWorker`重复数据删除，我们将启用功能标记`disable_authorized_projects_deduplication` .

从 ChatOps：

```
/chatops run feature set disable_authorized_projects_deduplication true 
```

从 rails 控制台：

```
Feature.enable!(:disable_authorized_projects_deduplication) 
```

## Job urgency[](#job-urgency "Permalink")

作业可以设置一个`urgency`属性，可以是`:high` ， `:low`或`:throttled` . 这些目标如下：

| **Urgency** | **队列调度目标** | **执行延迟要求** |
| --- | --- | --- |
| `:high` | 10 秒 | 1 秒的 p50、10 秒的 p99 |
| `:low` | 1 分钟 | 最长运行时间为 5 分钟 |
| `:throttled` | None | 最长运行时间为 5 分钟 |

要设置作业的紧急程度，请使用`urgency`类方法：

```
class HighUrgencyWorker
  include ApplicationWorker

  urgency :high

  # ...
end 
```

### Latency sensitive jobs[](#latency-sensitive-jobs "Permalink")

如果立即安排大量后台作业，则在作业等待辅助节点可用时，可能会出现作业排队. 这是正常现象，它可以通过系统地处理流量高峰来赋予系统弹性. 但是，某些作业比其他作业对延迟更敏感. 这些工作的示例包括：

1.  在推送到分支之后更新合并请求的作业.
2.  在推送到分支之后，该任务会使项目的已知分支的缓存无效.
3.  更改权限后，用户可以看到重新计算组和项目的作业.
4.  在状态更改为管道中的作业之后更新 CI 管道状态的作业.

当这些作业被延迟时，用户可能会将延迟视为错误：例如，他们可以推送分支，然后尝试为该分支创建合并请求，但在 UI 中被告知该分支不存在. 我们认为这些工作很`urgency :high`

做出额外的努力以确保这些作业在计划后的很短时间内启动. 但是，为了确保吞吐量，这些作业还具有非常严格的执行持续时间要求：

1.  中位作业执行时间应少于 1 秒.
2.  99％的工作应在 10 秒内完成.

如果一个工作人员不能满足这些期望，那么就不能将其视为`urgency :high`工作人员：考虑重新设计该工作人员，或在两个不同的工作人员之间拆分工作，其中一个工作`urgency :high`执行快速的`urgency :high`代码，另一个工作`urgency :low` ，它没有执行延迟要求（但也有较低的调度目标）.

### Changing a queue’s urgency[](#changing-a-queues-urgency "Permalink")

在 GitLab.com，我们几个跑 Sidekiq [碎片](https://dashboards.gitlab.net/d/sidekiq-shard-detail/sidekiq-shard-detail) ，其中每一个代表一个特定类型的工作负载.

更改队列的紧急性或添加新队列时，我们需要考虑新分片上的预期工作量. 请注意，如果我们要更改现有队列，那么也会对旧分片产生影响，但这始终会减少工作量.

为此，我们要计算新分片的总执行时间和 RPS（吞吐量）的预期增长. 我们可以从以下获得这些值：

*   " [队列详细信息"仪表板](https://dashboards.gitlab.net/d/sidekiq-queue-detail/sidekiq-queue-detail)具有队列本身的值. 对于新队列，我们​​可以查找具有类似模式或在类似情况下安排的队列.
*   [碎片详细信息仪表板](https://dashboards.gitlab.net/d/sidekiq-shard-detail/sidekiq-shard-detail)具有总执行时间和吞吐量（RPS）. "分片利用率"面板将显示该分片当前是否有多余的容量.

然后，我们可以计算我们要更改的队列的 RPS *平均运行时间（针对新作业的估算值），以查看新分片期望的 RPS 和执行时间的相对增加：

```
new_queue_consumption = queue_rps * queue_duration_avg
shard_consumption = shard_rps * shard_duration_avg

(new_queue_consumption / shard_consumption) * 100 
```

如果我们预期增加**幅度小于 5％** ，则无需采取进一步措施.

否则，请对合并请求 ping `@gitlab-org/scalability`并要求进行审查.

## Jobs with External Dependencies[](#jobs-with-external-dependencies "Permalink")

GitLab 应用程序中的大多数后台作业都与其他 GitLab 服务进行通信. 例如，PostgreSQL，Redis，Gitaly 和对象存储. 这些被视为作业的"内部"依赖性.

但是，某些作业将依赖于外部服务才能成功完成. 一些示例包括：

1.  调用用户配置的 Web 钩子的作业.
2.  将应用程序部署到用户配置的 k8s 集群的作业.

这些作业具有"外部依赖性". 这对于后台处理群集的运行有多种重要的作用：

1.  大多数外部依赖项（例如 Web 钩子）都不提供 SLO，因此我们不能保证这些作业的执行延迟. 由于我们无法保证执行延迟，因此无法确保吞吐量，因此，在高流量环境中，我们需要确保将具有外部依赖关系的作业与高紧急性作业分开，以确保这些队列上的吞吐量.
2.  Errors in jobs with external dependencies have higher alerting thresholds as there is a likelihood that the cause of the error is external.

```
class ExternalDependencyWorker
  include ApplicationWorker

  # Declares that this worker depends on
  # third-party, external services in order
  # to complete successfully
  worker_has_external_dependencies!

  # ...
end 
```

**注意：**请注意，一项工作既不能具有很高的紧迫性，又不能具有外部依赖性.

## CPU-bound and Memory-bound Workers[](#cpu-bound-and-memory-bound-workers "Permalink")

受 CPU 或内存资源限制约束的工作程序应使用`worker_resource_boundary`方法进行注释.

大多数工作人员倾向于将大部分时间都花在阻止时间上，等待来自 Redis，PostgreSQL 和 Gitaly 等其他服务的网络响应. 由于 Sidekiq 是多线程环境，因此可以高并发地调度这些作业.

但是，有些工人在 Ruby 中花费大量时间*在 CPU*运行逻辑上. Ruby MRI 不支持真正的多线程-它依赖[GIL](https://thoughtbot.com/blog/untangling-ruby-threads#the-global-interpreter-lock)来极大简化应用程序开发，无论托管该进程的计算机有多少核，一次仅允许一个进程中的一部分 Ruby 代码运行一次. 对于受 IO 约束的工作人员，这不是问题，因为大多数线程在基础库（位于 GIL 之外）中被阻止.

如果许多线程试图同时运行 Ruby 代码，则将导致 GIL 争用，这将减慢所有进程的速度.

在高流量的环境中，知道一个工作人员受 CPU 限制，可以使我们在具有较低并发性的其他队列中运行它. 这样可以确保最佳性能.

同样，如果工作人员使用大量内存，则可以在定制的低并发，高内存队列上运行这些内存.

请注意，受内存限制的工作程序会创建大量的 GC 工作负载，暂停时间为 10-50ms. 这将对工作人员的延迟要求产生影响. 因此， `memory`限制， `urgency :high`作业是不允许的，并且将使 CI 失败. 通常，不鼓励受`memory`限制的工作人员，应考虑处理工作的替代方法.

如果工作程序需要大量的内存和 CPU 时间，则由于上述对高紧急性的内存绑定工作程序的限制，应将其标记为内存绑定.

## Declaring a Job as CPU-bound[](#declaring-a-job-as-cpu-bound "Permalink")

本示例说明如何将作业声明为受 CPU 约束.

```
class CPUIntensiveWorker
  include ApplicationWorker

  # Declares that this worker will perform a lot of
  # calculations on-CPU.
  worker_resource_boundary :cpu

  # ...
end 
```

## Determining whether a worker is CPU-bound[](#determining-whether-a-worker-is-cpu-bound "Permalink")

我们使用以下方法来确定工作程序是否受 CPU 限制：

*   在 Sidekiq 结构化 JSON 日志中，汇总工作`duration`和`cpu_s`字段.
*   `duration` refers to the total job execution duration, in seconds
*   `cpu_s`是从[`Process::CLOCK_THREAD_CPUTIME_ID`](https://www.rubydoc.info/stdlib/core/Process:clock_gettime)计数器派生的，它是作业在 CPU 上花费的时间的度量.
*   将`cpu_s`除以`duration`即可得到在 CPU 上花费的`duration`百分比.
*   如果该比例超过 33％，则认为该工作线程受 CPU 限制，因此应进行注释.
*   请注意，这些值不应用于较小的样本量，而应用于相当大的汇总.

## Feature category[](#feature-category "Permalink")

所有 Sidekiq 工作人员都必须定义一个已知的[特征类别](feature_categorization/index.html#sidekiq-workers) .

## Job weights[](#job-weights "Permalink")

某些作业的重量已声明. 仅在默认执行模式下运行 Sidekiq 时才使用此选项-使用[`sidekiq-cluster`](../administration/operations/extra_sidekiq_processes.html)不能计算权重.

随着我们[朝在 Core 中使用`sidekiq-cluster`迈进](https://gitlab.com/gitlab-org/gitlab/-/issues/34396) ，新增加的工作人员无需指定权重. 他们可以简单地使用默认权重 1.

## Worker context[](#worker-context "Permalink")

版本历史

*   在 GitLab 12.8 中[引入](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/9) .

为了在日志中获得有关工作程序的更多信息，我们[以`ApplicationContext`的形式向工作](logging.html#logging-context-metadata-through-rails-or-grape-requests)添加[元数据](logging.html#logging-context-metadata-through-rails-or-grape-requests) . 在大多数情况下，从请求计划作业时，该上下文已经从请求中扣除并添加到计划的作业中.

运行作业时，将还原计划时处于活动状态的上下文. 这会使上下文传播到正在运行的作业中计划的任何作业.

所有这些意味着在大多数情况下，要将上下文添加到作业中，我们无需执行任何操作.

但是，在某些情况下，计划作业时将不存在任何上下文，或者存在的上下文很可能不正确. 对于这些实例，我们添加了 Rubocop 规则以引起注意并避免日志中的元数据不正确.

与大多数警察一样，有完全正当的理由禁用它们. 在这种情况下，可能来自请求的上下文是正确的. 或者，您可能已经以警察无法接受的方式指定了上下文. 无论如何，请在禁用警察时留下指向将使用哪个上下文的代码注释.

当确实为上下文提供对象时，请确保已预先加载名称空间和项目的路由. 这可以通过使用来完成`.with_route`上所有定义范围`Routable`秒.

### Cron workers[](#cron-workers "Permalink")

对于 Cronjob 队列（ `include CronjobQueue` ）中的工作人员，将自动清除上下文，即使从请求中安排工作人员时也是如此. 我们这样做是为了避免从 cron worker 安排其他作业时出现不正确的元数据.

Cron 工作人员自己在实例范围内运行，因此它们的作用域不限于应添加到上下文中的用户，名称空间，项目或其他资源.

然而，他们往往安排*确实*需要方面的其他工作.

这就是为什么需要在工作人员中某处显示上下文的原因. 可以通过在工作器内的某些位置使用以下方法之一来完成此操作：

1.  在`with_context`帮助器中包装用于调度作业的代码：

    ```
     def perform
        deletion_cutoff = Gitlab::CurrentSettings
                            .deletion_adjourned_period.days.ago.to_date
        projects = Project.with_route.with_namespace
                     .aimed_for_deletion(deletion_cutoff)

        projects.find_each(batch_size: 100).with_index do |project, index|
          delay = index * INTERVAL

          with_context(project: project) do
            AdjournedProjectDeletionWorker.perform_in(delay, project.id)
          end
        end
      end 
    ```

2.  使用提供上下文的批处理调度方法：

    ```
     def schedule_projects_in_batch(projects)
        ProjectImportScheduleWorker.bulk_perform_async_with_contexts(
          projects,
          arguments_proc: -> (project) { project.id },
          context_proc: -> (project) { { project: project } }
        )
      end 
    ```

    或者，在延迟调度时：

    ```
     diffs.each_batch(of: BATCH_SIZE) do |diffs, index|
        DeleteDiffFilesWorker
          .bulk_perform_in_with_contexts(index *  5.minutes,
                                         diffs,
                                         arguments_proc: -> (diff) { diff.id },
                                         context_proc: -> (diff) { { project: diff.merge_request.target_project } })
      end 
    ```

### Jobs scheduled in bulk[](#jobs-scheduled-in-bulk "Permalink")

通常，在批量调度作业时，这些作业应具有单独的上下文而不是总体上下文.

如果是这样的话， `bulk_perform_async`可以通过更换`bulk_perform_async_with_context`帮手，而不是`bulk_perform_in`使用`bulk_perform_in_with_context` .

例如：

```
 ProjectImportScheduleWorker.bulk_perform_async_with_contexts(
      projects,
      arguments_proc: -> (project) { project.id },
      context_proc: -> (project) { { project: project } }
    ) 
```

第一个参数中可枚举的每个对象分为两个块：

*   `arguments_proc` ，它需要返回作业需要调度的参数列表.

*   需要返回带有作业上下文信息的哈希值的`context_proc` .

## Arguments logging[](#arguments-logging "Permalink")

当[`SIDEKIQ_LOG_ARGUMENTS`](../administration/troubleshooting/sidekiq.html#log-arguments-to-sidekiq-jobs)启用，Sidekiq 作业参数将被记录.

默认情况下，记录的唯一参数是数字参数，因为其他类型的参数可能包含敏感信息. 要覆盖此参数，请在工作程序内部使用`loggable_arguments`并记录要记录的参数的索引. （此处不需要指定数字参数.）

例如：

```
class MyWorker
  include ApplicationWorker

  loggable_arguments 1, 3

  # object_id will be logged as it's numeric
  # string_a will be logged due to the loggable_arguments call
  # string_b will be filtered from logs
  # string_c will be logged due to the loggable_arguments call
  def perform(object_id, string_a, string_b, string_c)
  end
end 
```

## Tests[](#tests "Permalink")

与其他任何类一样，每个 Sidekiq 工作者都必须使用 RSpec 进行测试. 这些测试应放在`spec/workers` .

## Sidekiq Compatibility across Updates[](#sidekiq-compatibility-across-updates "Permalink")

请记住，Sidekiq 作业的参数在计划执行时存储在队列中. 在线更新期间，这可能会导致几种可能的情况：

1.  该应用程序的较旧版本发布作业，该作业由升级的 Sidekiq 节点执行.
2.  作业在升级之前排队，但在升级之后执行.
3.  作业由运行较新版本应用程序的节点排队，但在运行较旧版本应用程序的节点上执行.

### Changing the arguments for a worker[](#changing-the-arguments-for-a-worker "Permalink")

作业需要在应用程序的连续版本之间向后和向前兼容. 在所有 Rails 和 Sidekiq 节点都具有更新的代码之前，添加或删除参数可能会在部署期间引起问题.

#### Remove an argument[](#remove-an-argument "Permalink")

**不要从`perform`函数中删除参数.** . 而是，使用以下方法：

1.  提供默认值（通常为`nil` ）并使用注释将参数标记为已弃用
2.  停止在`perform_async`使用该参数.
3.  忽略 worker 类中的值，但是直到下一个主要版本才将其删除.

在以下示例中，如果要删除`arg2` ，请首先设置`nil`默认值，然后更新调用`ExampleWorker.perform_async`位置.

```
class ExampleWorker
  def perform(object_id, arg1, arg2 = nil)
    # ...
  end
end 
```

#### Add an argument[](#add-an-argument "Permalink")

有两种方法可以安全地向 Sidekiq 工作者添加新参数：

1.  Set up a [multi-step deployment](#multi-step-deployment) in which the new argument is first added to the worker
2.  将[参数哈希](#parameter-hash)用于其他参数. 这也许是最灵活的选择.

##### Multi-step deployment[](#multi-step-deployment "Permalink")

这种方法需要多个合并请求，并且在合并其他更改之前，要合并和部署第一个合并请求.

1.  在初始合并请求中，使用默认值将参数添加到 worker 中：

    ```
     class ExampleWorker
       def perform(object_id, new_arg = nil)
         # ...
       end
     end 
    ```

2.  使用新参数合并和部署工作程序.
3.  在另一个合并请求中，更新`ExampleWorker.perform_async`调用以使用新参数.

##### Parameter hash[](#parameter-hash "Permalink")

如果现有工作人员已经利用参数哈希，则此方法将不需要多次部署.

1.  在 worker 中使用参数散列以实现将来的灵活性：

    ```
     class ExampleWorker
       def perform(object_id, params = {})
         # ...
       end
     end 
    ```

### Removing workers[](#removing-workers "Permalink")

尽量避免在次要版本和修补程序版本中删除工作人员及其队列.

在联机更新期间，实例可能有待处理的作业，而删除队列可能导致这些作业永远卡住. 如果您无法为这些 Sidekiq 作业编写迁移，请考虑仅在主要版本中删除该工作程序.

### Renaming queues[](#renaming-queues "Permalink")

出于同样的原因，遣散工人也很危险，因此在重命名队列时应格外小心.

重命名队列时，请使用`sidekiq_queue_migrate`帮助程序迁移方法，如本示例所示：

```
class MigrateTheRenamedSidekiqQueue < ActiveRecord::Migration[5.0]
  include Gitlab::Database::MigrationHelpers

  DOWNTIME = false

  def up
    sidekiq_queue_migrate 'old_queue_name', to: 'new_queue_name'
  end

  def down
    sidekiq_queue_migrate 'new_queue_name', to: 'old_queue_name'
  end
end 
```