mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-11 22:38:54 +00:00
92a132d74f
The last piece of the #1687 follow-up. BuildZipDownloadJob allows itself an hour, every shipped topology runs exactly one worker, and everything shares the default queue -- so one large archive delayed every notification email queued behind it. The size cap and the one-build-per-person rule bounded that in July; they did not remove it. onQueue('zips') in the constructor rather than at the dispatch site, so a second caller cannot forget it. Both images grow a worker for it: compose.yaml gains worker-zips, supervisord gains [program:queue-zips], and the existing worker in each narrows to --queue=default. --tries=1 there matches the job, which records its own failure rather than being retried. The part that needs care is the manual install. A worker whose command still says plain `queue:work` consumes `default` only, so it would send email happily and never finish a single zip, with nothing in any log saying why. INSTALL.md's unit now reads --queue=default,zips -- one worker watching both, which is right for most installations -- and says what happens if you leave it off, with the two-worker split offered for anyone who would rather keep the two kinds of work apart. CHANGELOG carries it as an upgrade note, since it is something to do rather than something that was done. Verified in the dev stack rather than only in a test: dispatched a build and watched worker-zips take it while the default worker stayed idle.
175 lines
5.4 KiB
YAML
175 lines
5.4 KiB
YAML
name: projectsend
|
|
|
|
services:
|
|
app:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
volumes:
|
|
- .:/var/www/html
|
|
# Shared dev clones of the companion packages — never nested inside this
|
|
# repo. Relative to keep host and container paths symmetric with
|
|
# the ../packages symlink at this repo's own root.
|
|
- ../packages:/var/www/packages
|
|
environment:
|
|
PHP_IDE_CONFIG: serverName=projectsend
|
|
# Optional unattended first-admin creation; without these the web
|
|
# setup screen prompts on first visit.
|
|
ADMIN_NAME: ${ADMIN_NAME:-}
|
|
ADMIN_EMAIL: ${ADMIN_EMAIL:-}
|
|
ADMIN_PASSWORD: ${ADMIN_PASSWORD:-}
|
|
# The whole default stack declares one, so it comes back after a reboot
|
|
# or a Docker restart instead of half of it coming back — the confusing
|
|
# state, where the queue runs and the site is down (#1658). The dev-only
|
|
# profile services below deliberately do not: you bring those up for a
|
|
# session, not for the life of the machine.
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
web:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/web/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
ports:
|
|
- "${APP_PORT:-8090}:80"
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ./docker/web/nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
|
restart: unless-stopped
|
|
depends_on:
|
|
- app
|
|
|
|
worker:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
command: php artisan queue:work --queue=default --tries=3 --backoff=3
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ../packages:/var/www/packages
|
|
# Required so `queue:restart` (triggered when mail provider settings
|
|
# are saved) actually brings the worker back instead of leaving the
|
|
# queue dead until someone runs `docker compose up -d` by hand.
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
# Zip builds get their own worker: BuildZipDownloadJob allows itself an
|
|
# hour, and on a shared queue one large archive holds up every
|
|
# notification email behind it.
|
|
worker-zips:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
command: php artisan queue:work --queue=zips --tries=1
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ../packages:/var/www/packages
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
scheduler:
|
|
build:
|
|
context: .
|
|
dockerfile: docker/app/Dockerfile
|
|
args:
|
|
WWWUSER: ${WWWUSER:-1000}
|
|
WWWGROUP: ${WWWGROUP:-1000}
|
|
command: php artisan schedule:work
|
|
volumes:
|
|
- .:/var/www/html
|
|
- ../packages:/var/www/packages
|
|
# Same reason the worker has one, plus a second: on a fresh clone this
|
|
# exits until `composer install` has run, and without a restart policy it
|
|
# then stays exited — scheduled work silently never happens, on the one
|
|
# setup where nobody would think to check.
|
|
restart: unless-stopped
|
|
depends_on:
|
|
db:
|
|
condition: service_healthy
|
|
redis:
|
|
condition: service_started
|
|
|
|
db:
|
|
image: mysql:8.4
|
|
command: --mysql-native-password=OFF
|
|
environment:
|
|
MYSQL_DATABASE: ${DB_DATABASE:-projectsend}
|
|
MYSQL_USER: ${DB_USERNAME:-projectsend}
|
|
MYSQL_PASSWORD: ${DB_PASSWORD:-secret}
|
|
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root}
|
|
volumes:
|
|
- db-data:/var/lib/mysql
|
|
restart: unless-stopped
|
|
ports:
|
|
# Loopback only: this forward exists for host-side DB GUIs, not for
|
|
# the network. Without the prefix Docker publishes on 0.0.0.0 and
|
|
# bypasses most host firewalls — a LAN-reachable MySQL with the
|
|
# compose-file default password on any host that runs the stack.
|
|
- "127.0.0.1:${DB_PORT_FORWARD:-33061}:3306"
|
|
healthcheck:
|
|
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${DB_ROOT_PASSWORD:-root}"]
|
|
interval: 5s
|
|
timeout: 3s
|
|
retries: 10
|
|
|
|
redis:
|
|
image: redis:7-alpine
|
|
restart: unless-stopped
|
|
volumes:
|
|
- redis-data:/data
|
|
|
|
# Dev-only DB GUI (brief §12: ship Adminer as a dev-only Compose service)
|
|
adminer:
|
|
image: adminer:latest
|
|
ports:
|
|
# Loopback only — an unauthenticated DB panel must not be reachable
|
|
# from the network just because someone brought the dev profile up
|
|
# on a machine with a routable address.
|
|
- "127.0.0.1:${ADMINER_PORT:-8091}:8080"
|
|
environment:
|
|
ADMINER_DEFAULT_SERVER: db
|
|
depends_on:
|
|
- db
|
|
profiles:
|
|
- dev
|
|
|
|
# Dev-only SMTP catcher: lets email notifications be sent and inspected
|
|
# locally (web UI + HTTP API) without a real mail server.
|
|
mailpit:
|
|
image: axllent/mailpit:latest
|
|
ports:
|
|
# Loopback only, same reasoning as Adminer: captured mail is readable
|
|
# without authentication.
|
|
- "127.0.0.1:${MAILPIT_SMTP_PORT:-1025}:1025"
|
|
- "127.0.0.1:${MAILPIT_WEB_PORT:-8025}:8025"
|
|
profiles:
|
|
- dev
|
|
|
|
volumes:
|
|
db-data:
|
|
redis-data:
|