622.md 25.0 KB
Newer Older
Lab机器人's avatar
readme  
Lab机器人 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
# 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 
```