# HAProxy 前置时的瞬时 503 错误

**URL:** <https://meta.discourse.org/t/transient-503s-after-launcher-rebuild-appn-when-they-re-fronted-by-haproxy/383179>\
**Category:** Self-hosting\
**Tags:** advanced-setup, hosting\
**Created:** [2025年九月18日 19:34 UTC](https://meta.discourse.org/t/transient-503s-after-launcher-rebuild-appn-when-they-re-fronted-by-haproxy/383179 "2025-09-18T19:34:16Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)\
**Post date:** [2025年九月18日 19:34 UTC](https://meta.discourse.org/t/transient-503s-after-launcher-rebuild-appn-when-they-re-fronted-by-haproxy/383179/1 "2025-09-18T19:34:16Z")

</div>

我创建了一个测试论坛，其中包含两个 `web_only` 容器、一个 `mail-receiver` 容器、Postgres 和 Redis，它们都在 Docker 网络上。两个 Web 容器 nginx 都由 HAProxy 提供前端服务。它们运行良好，但我发现在重建两个 Web 容器之一时，总会有短暂的停机时间，并返回 503。

幸运的是，我找到了一个缓解的变通方法，但并不完美；

* * *

在重建 `app1` 之前，运行

`echo “disable server be_discourse/app1” | socat stdio /run/haproxy/admin.sock`

然后在 `app1` 的重建过程完成后，运行

`echo “enable server be_discourse/app1” | socat stdio /run/haproxy/admin.sock`

* * *

反之，要重建 `app2`，运行

`echo “disable server be_discourse/app2” | socat stdio /run/haproxy/admin.sock`

然后在 `app2` 的重建过程完成后，运行

`echo “enable server be_discourse/app1” | socat stdio /run/haproxy/admin.sock`

* * *

这基于 `/etc/haproxy/haproxy.cfg` 中与 `be_discourse` 匹配，我暂时不会将配置文件粘贴到代码块中，但如果大多数人都想要，我可能会这样做。

因此，这通过告知 HAProxy 在容器出现 503 错误之前将流量转移来缓解 503 错误。

* * *

你也可以创建一个错误页面，但我对此不太成功，并且觉得需要进一步研究。但是，这并没有真正解决停机问题。

---

<div class="post-metadata">

**Author:** ![RGJ](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rgj/32/523185_2.png) [@RGJ](https://meta.discourse.org/u/RGJ)\
**Post date:** [2025年九月18日 19:51 UTC](https://meta.discourse.org/t/transient-503s-after-launcher-rebuild-appn-when-they-re-fronted-by-haproxy/383179/2 "2025-09-18T19:51:45Z")

</div>

为什么不在出现 503 时[重新分发](https://www.haproxy.com/documentation/haproxy-configuration-tutorials/reliability/retries/#redispatch-to-a-different-server)到下一台服务器？

---

<div class="post-metadata">

**Author:** ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)\
**Post date:** [2025年九月18日 20:00 UTC](https://meta.discourse.org/t/transient-503s-after-launcher-rebuild-appn-when-they-re-fronted-by-haproxy/383179/3 "2025-09-18T20:00:09Z")

</div>

太好了！那会很好。另外，您对 sidekiq 有什么建议吗？我在 [discourse\_docker/samples at main · discourse/discourse\_docker · GitHub](https://github.com/discourse/discourse_docker/tree/main/samples) 中完全看不到 sidekiq，这导致我对手动更改 yml 文件进行了以下更改：

* * *

`app1.yml`

```diff
## 记住，这是 YAML 语法 - 您只能有一个名为的块
run:
  - exec: echo "Beginning of custom commands"
+ - exec: rm -f /etc/service/sidekiq/down
  ## 如果您想为 root 配置密码登录，请取消注释并更改：

```

* * *

`app2.yml`

```diff
## 记住，这是 YAML 语法 - 您只能有一个名为的块
run:
  - exec: echo "Beginning of custom commands"
+ - exec: bash -lc 'mkdir -p /etc/service/sidekiq && touch /etc/service/sidekiq/down'
  ## 如果您想为 root 配置密码登录，请取消注释并更改：

```

---

<div class="post-metadata">

**Author:** ![Ethsim2](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ethsim2/32/522255_2.png) [@Ethsim2](https://meta.discourse.org/u/Ethsim2)\
**Post date:** [2025年九月18日 20:32 UTC](https://meta.discourse.org/t/transient-503s-after-launcher-rebuild-appn-when-they-re-fronted-by-haproxy/383179/4 "2025-09-18T20:32:41Z")

</div>

对于运行多个 Web 容器的任何人来说，还有一个额外的需要考虑的点是 **Sidekiq 的运行位置** 。

503 错误只会影响 Web 请求，但如果 Sidekiq 宕机，您的网站将悄无声息地停止处理后台作业（电子邮件、摘要、徽章、Webhooks）。处理此问题的一个巧妙方法是为 Sidekiq 分配自己的容器，并将其在 Web 节点上禁用。

Discourse 在底层使用 _runit_：`/etc/service/*` 中的每个服务都会启动，除非在其目录中存在一个名为 `down` 的文件。这就是所需的全部控制。

以下是一个专用 Sidekiq worker 的示例：

> **worker.yml — 仅 Sidekiq**
>
> ```yml
> templates:
> - "templates/postgres.template.yml"
> - "templates/redis.template.yml"
> - "templates/sshd.template.yml"
> - "templates/web.template.yml"
> - "templates/web.ratelimited.template.yml"
> 
> expose: [] # no HTTP ports
> env:
> DISCOURSE_DB_HOST: data
> DISCOURSE_REDIS_HOST: data
> DISCOURSE_HOSTNAME: "forum.example.com"
> # match your existing secrets / SMTP settings
> hooks:
> after_code:
> - exec:
> cd: $home
> cmd:
> # disable web services
> - mkdir -p /etc/service/puma && touch /etc/service/puma/down
> - mkdir -p /etc/service/nginx && touch /etc/service/nginx/down
> # enable Sidekiq
> - rm -f /etc/service/sidekiq/down
> run:
> - exec: echo "Starting Sidekiq worker container"
> 
> ```

在 Web 容器（app1/app2）上，应执行相反的操作 - 保持 Puma 和 Nginx 启用，但添加：

```yml
hooks:
  after_code:
    - exec:
        cd: $home
        cmd:
          - mkdir -p /etc/service/sidekiq && touch /etc/service/sidekiq/down

```

通过这种设置，HAProxy 只负责平衡 Web 容器，而 Sidekiq 则在 worker 中继续运行。这样，当您重建或轮换 Web 节点时，后台作业不会中断。

---

<div class="post-metadata">

**Author:** ![tobiaseigen](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/tobiaseigen/32/539204_2.png) [@tobiaseigen](https://meta.discourse.org/u/tobiaseigen)\
**Post date:** [2025年九月26日 17:04 UTC](https://meta.discourse.org/t/transient-503s-after-launcher-rebuild-appn-when-they-re-fronted-by-haproxy/383179/5 "2025-09-26T17:04:39Z")

</div>

我已将此移至 #Installation > Hosting，因为它似乎是一个开放式对话。让我们避免在 #Support 中创建此类对话。
