fix(matrix): recreate synapse and the bridges together on a swarm redeploy

Every deploy of the compose flavour wipes /opt/compose/matrix/mautrix/ and
re-renders each bridge config with placeholder tokens, so the bridges generate
new registrations on their next start and synapse has to load them. Compose
gets that ordering from the `compose down` right before the wipe. Swarm had no
counterpart: the bridge services kept running on the deleted bind-mount
directories and never regenerated anything, while synapse was restarted by the
flush and found no registration.

Job 102705652096 of run 34421944328 (swarm, variant 2) hits it on the
credential-rotation redeploy, which changes homeserver.yaml, a swarm config,
and therefore restarts synapse every time:

    FileNotFoundError: [Errno 2] No such file or directory: '/data/mautrix-meta/registration.yaml'
    stuck: matrix_synapse

From 05:44:56 dockerd reported "current working directory is outside of
container mount namespace root" for the running slack and signal bridges, and
mautrix-meta, started at 03:50:50, only initialised again at 05:53:11, when its
healthcheck finally replaced it; stack_ready.sh had given up at its 180s grace
long before.

Before the wipe, swarm mode now removes the synapse and bridge services a
previous deploy left running, once from the stack host, so the flush's
`docker stack deploy` creates them together, exactly as on a first deploy
(which converged in about 32s in the same job). Removing only the bridges would
not be enough: a synapse that is not recreated keeps the old tokens, and the
new bridges would be refused before the synapse restart at the end of the file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
kevinveenbirkenbachandClaude Opus 5 committed 2026-09-10 12:32:27 +02:00
1 parent 347904c04a
commit 93735fd533
1 file changed
+32
@@ -20,6 +20,38 @@
chdir: "{{ lookup('container', application_id, 'directories.instance') }}"
when: DEPLOYMENT_MODE == 'compose'
- when:
- DEPLOYMENT_MODE == 'swarm'
- MATRIX_BRIDGES | length > 0
delegate_to: "{{ STACK_HOST }}"
run_once: true
timeout: "{{ lookup('timeout', 60) | int }}"
block:
- name: "🔍 List the services a previous swarm deploy left running"
ansible.builtin.command:
argv:
- container
- service
- ls
- --filter
- "label=com.docker.stack.namespace={{ application_id | get_entity_name }}"
- --format
- "{{ '{{.Name}}' }}"
register: matrix_swarm_services
changed_when: false
- name: "🐝 Remove synapse and the bridges before their registrations are wiped"
ansible.builtin.command:
argv: "{{ ['container', 'service', 'rm'] + matrix_swarm_registration_services }}"
vars:
matrix_swarm_registration_services: >-
{{ ([MATRIX_SYNAPSE_SERVICE]
+ (MATRIX_BRIDGES | map(attribute='bridge_name')
| map('regex_replace', '^', (application_id | get_entity_name) ~ '_mautrix-') | list))
| select('in', matrix_swarm_services.stdout_lines) | list }}
changed_when: true
when: matrix_swarm_registration_services | length > 0
- name: "🧹 cleanup project folder"
file:
path: "{{ lookup('container', application_id, 'directories.instance') }}mautrix/"