Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .ddev/addon-metadata/redis/manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: redis
repository: ddev/ddev-redis
version: v2.2.0
install_date: "2026-09-08T02:37:13Z"
project_files:
- docker-compose.redis.yaml
- redis/scripts/settings.ddev.redis.php
- redis/scripts/setup-drupal-settings.sh
- redis/scripts/setup-redis-optimized-config.sh
- redis/redis.conf
- redis/advanced.conf
- redis/append.conf
- redis/general.conf
- redis/io.conf
- redis/memory.conf
- redis/network.conf
- redis/security.conf
- redis/snapshots.conf
- commands/host/redis-backend
- commands/redis/redis-cli
- commands/redis/redis-flush
global_files: []
removal_actions:
- |
#ddev-description:Remove redis settings if applicable
files=(
"${DDEV_APPROOT}/${DDEV_DOCROOT}/sites/default/settings.ddev.redis.php"
"${DDEV_APPROOT}/.ddev/docker-compose.redis_extra.yaml"
)
for file in "${files[@]}"; do
if [ -f "$file" ]; then
if grep -q '#ddev-generated' "$file"; then
rm -f "$file"
else
echo "Unwilling to remove '$file' because it does not have #ddev-generated in it; you can manually delete it if it is safe to delete."
fi
fi
done
124 changes: 124 additions & 0 deletions .ddev/commands/host/redis-backend
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
#!/usr/bin/env bash
#ddev-generated

## Description: Use a different key-value store for Redis
## Usage: redis-backend <image> [optimize]
## Example: ddev redis-backend redis-alpine optimize

REDIS_DOCKER_IMAGE=${1:-}
REDIS_CONFIG=${2:-}
NAME=$REDIS_DOCKER_IMAGE

function show_help() {
cat <<EOF
Usage: ddev redis-backend <image|alias> [optimize]

Choose from predefined aliases, or provide any Redis-compatible Docker image.
Note that not every Docker image can work right away, and you may need to override
the "command:" in the docker-compose.redis_extra.yaml file

Available aliases:
redis redis:7
redis-alpine redis:7-alpine
valkey valkey/valkey:8
valkey-alpine valkey/valkey:8-alpine

Custom backend:
You can specify any Docker image, e.g.:
ddev redis-backend redis:6

Optional:
optimize Apply additional Redis configuration with resource limits
optimized Same as optimize

Examples:
ddev redis-backend redis-alpine optimize
ddev redis-backend valkey
ddev redis-backend redis:7.2-alpine
EOF
exit 0
}

function optimize_config() {
[[ "$REDIS_CONFIG" != "optimized" && "$REDIS_CONFIG" != "optimize" ]] && return
ddev dotenv set .ddev/.env.redis --redis-optimized=true
}

function change_hostname() {
[[ "${REDIS_HOSTNAME:-}" == "" ]] && return
ddev dotenv set .ddev/.env.redis --redis-hostname="$REDIS_HOSTNAME"
}

function cleanup() {
rm -f "$DDEV_APPROOT/.ddev/.env.redis"
rm -rf "$DDEV_APPROOT/.ddev/redis/"
rm -f "$DDEV_APPROOT/.ddev/docker-compose.redis.yaml" "$DDEV_APPROOT/.ddev/docker-compose.redis_extra.yaml"

redis_volume="ddev-$(ddev status -j | docker run -i --rm ddev/ddev-utilities jq -r '.raw.name')_redis"
if docker volume ls -q | grep -qw "$redis_volume"; then
ddev stop
docker volume rm "$redis_volume"
fi
}

function check_docker_image() {
echo "Pulling ${REDIS_DOCKER_IMAGE}..."
if ! docker pull "$REDIS_DOCKER_IMAGE"; then
echo >&2 "❌ Unable to pull ${REDIS_DOCKER_IMAGE}"
exit 2
fi
}

function use_docker_image() {
[[ "$REDIS_DOCKER_IMAGE" != "redis:7" ]] && ddev dotenv set .ddev/.env.redis --redis-docker-image="$REDIS_DOCKER_IMAGE"
REPO=$(ddev add-on list --installed -j 2>/dev/null | docker run -i --rm ddev/ddev-utilities jq -r '.raw[] | select(.Name=="redis") | .Repository // empty' 2>/dev/null)
ddev add-on get "${REPO:-ddev/ddev-redis}"
}

case "$REDIS_DOCKER_IMAGE" in
redis)
NAME="Redis 7"
REDIS_DOCKER_IMAGE="redis:7"
;;
redis-alpine)
NAME="Redis 7 Alpine"
REDIS_DOCKER_IMAGE="redis:7-alpine"
;;
valkey)
NAME="Valkey 8"
REDIS_DOCKER_IMAGE="valkey/valkey:8"
REDIS_HOSTNAME="valkey"
;;
valkey-alpine)
NAME="Valkey 8 Alpine"
REDIS_DOCKER_IMAGE="valkey/valkey:8-alpine"
REDIS_HOSTNAME="valkey"
;;
""|--help|-h)
show_help
;;
*)
NAME="$REDIS_DOCKER_IMAGE"
# Allow unknown image, nothing to override
;;
esac

check_docker_image
cleanup
optimize_config
change_hostname
use_docker_image

echo
echo "✅ Redis backend: $REDIS_DOCKER_IMAGE"
if [[ "$REDIS_CONFIG" == "optimized" || "$REDIS_CONFIG" == "optimize" ]]; then
echo "⚙️ Redis config: optimized"
else
echo "⚙️ Redis config: default"
fi

echo
echo "📝 Commit the '.ddev' directory to version control"

echo
echo "🔄 Redis config available after 'ddev restart'"
13 changes: 13 additions & 0 deletions .ddev/commands/redis/redis-cli
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env sh

#ddev-generated
## Description: Run redis-cli inside the Redis container
## Usage: redis-cli [flags] [args]
## Example: "ddev redis-cli KEYS *" or "ddev redis-cli INFO" or "ddev redis-cli --version"
## Aliases: redis

if [ -f /etc/redis/conf/security.conf ]; then
redis-cli -p 6379 -h "${REDIS_HOSTNAME:-redis}" -a redis --no-auth-warning $@
else
redis-cli -p 6379 -h "${REDIS_HOSTNAME:-redis}" $@
fi
12 changes: 12 additions & 0 deletions .ddev/commands/redis/redis-flush
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env sh

#ddev-generated
## Description: Flush all cache inside the Redis container
## Usage: redis-flush
## Example: "ddev redis-flush"

if [ -f /etc/redis/conf/security.conf ]; then
redis-cli -p 6379 -h "${REDIS_HOSTNAME:-redis}" -a redis --no-auth-warning FLUSHALL ASYNC
else
redis-cli -p 6379 -h "${REDIS_HOSTNAME:-redis}" FLUSHALL ASYNC
fi
69 changes: 69 additions & 0 deletions .ddev/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
name: convoy4x
type: laravel
docroot: public
php_version: "8.2"
webserver_type: nginx-fpm

# 4.x ships MySQL (docker-compose.yml pins mysql:8.0), unlike 5.x's Postgres.
database:
type: mysql
version: "8.0"

# Without this DDEV assigns a random ephemeral host port on every start, which
# breaks saved connections in GUI clients (TablePlus, DataGrip, mysql aliases).
host_db_port: "3306"

# The release workflow builds on Node 20.
nodejs_version: "20"
corepack_enable: false

# ext-gmp is required by composer.json. Without it `composer install` fails its
# platform check -- and `ddev composer` still exits 0, so vendor/ silently stays
# stale and every artisan call dies on the next platform_check.php.
webimage_extra_packages:
- php8.2-gmp

# MySQL + redis + mail overrides. These are real container env vars, so they
# take precedence over .env (Laravel's Dotenv does not overwrite existing env).
# Note CACHE_DRIVER, not 5.x's CACHE_STORE: this branch is on Laravel 11 but
# still ships the pre-11 config/cache.php, which reads the old key.
web_environment:
- APP_URL=https://convoy4x.ddev.site
- DB_CONNECTION=mysql
- DB_HOST=db
- DB_PORT=3306
- DB_DATABASE=db
- DB_USERNAME=db
- DB_PASSWORD=db
- REDIS_HOST=redis
- REDIS_PORT=6379
- REDIS_PASSWORD=
- CACHE_DRIVER=redis
- QUEUE_CONNECTION=redis
- SESSION_DRIVER=redis
- MAIL_MAILER=smtp
- MAIL_HOST=localhost
- MAIL_PORT=1025

# Deliberately no `db_test` database, unlike 5.x. This branch's tests/Pest.php
# uses DatabaseTransactions rather than RefreshDatabase, so they run against
# whatever is in the dev database and roll their own writes back. That means
# seeded dev data is visible to the suite and will fail any test asserting on a
# fleet-wide aggregate (the overview endpoint's counts, most of all). Run
# `ddev artisan migrate:fresh` before a full run, or scope to one file.

# Replaces the compose `workers` service and its scheduler.
web_extra_daemons:
- name: horizon
command: "php artisan horizon"
directory: /var/www/html
- name: scheduler
command: "php artisan schedule:work"
directory: /var/www/html

# Expose the Vite dev server, which vite.config.js pins to 1234.
web_extra_exposed_ports:
- name: vite
container_port: 1234
http_port: 1235
https_port: 1234
27 changes: 27 additions & 0 deletions .ddev/docker-compose.redis.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ddev-generated
services:
redis:
container_name: ddev-${DDEV_SITENAME}-redis
image: ${REDIS_DOCKER_IMAGE:-redis:7}
hostname: ${REDIS_HOSTNAME:-redis}
# These labels ensure this service is discoverable by ddev.
labels:
com.ddev.site-name: ${DDEV_SITENAME}
com.ddev.approot: ${DDEV_APPROOT}
restart: "no"
expose:
- 6379
volumes:
- ".:/mnt/ddev_config"
- "ddev-global-cache:/mnt/ddev-global-cache"
- "./redis:/etc/redis/conf"
- "redis:/data"
command: /etc/redis/conf/redis.conf
x-ddev:
describe-url-port: |
Backend: ${REDIS_DOCKER_IMAGE:-redis:7}
describe-info: |
Pass: <none>

volumes:
redis:
13 changes: 13 additions & 0 deletions .ddev/redis/redis.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Redis configuration.
# #ddev-generated
# Example configuration files for reference:
# http://download.redis.io/redis-stable/redis.conf
# http://download.redis.io/redis-stable/sentinel.conf

maxmemory 2048mb
maxmemory-policy allkeys-lfu

# to disable Redis persistence, remove ddev-generated from this file,
# and uncomment the two lines below:
#appendonly no
#save ""
65 changes: 65 additions & 0 deletions .sbx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# sbx kits

Provisioning for running a coding agent in a [Docker Sandbox](https://docs.docker.com/ai/sandboxes/)
(`sbx`) against this repo. sbx has no auto-detection for repo-local kits, so a kit
is just a committed directory you reference explicitly with `--kit`.

## `dev/` — Convoy 4.x dev environment

Installs ddev and starts the stack inside the sandbox (its Docker daemon, DB, and
volumes are isolated from your host ddev). It also sets up headless browsing:
Playwright is pinned and installed to `/opt/sbx-e2e` (never the repo), and
`dev/browser.mjs` is published to `/opt/sbx-e2e/browser.mjs` for scripts to import.
Because `/etc/hosts` is a read-only mount in a sandbox — which otherwise makes
`ddev start` fail outright — a startup step overmounts a writable copy so ddev can
register `*.ddev.site`.

```sh
sbx run --kit .sbx/dev claude
```

The first run installs ddev and pulls its images (slow, once). To make later
starts instant, snapshot the provisioned sandbox into a template:

```sh
sbx template save convoy4x-dev
sbx run -t convoy4x-dev --kit .sbx/dev claude # install is now a no-op; only `ddev start` runs
```

Then finish app provisioning inside the sandbox (see the kit's `agentContext`, or
`.sbx/dev/spec.yaml`):

```sh
ddev composer install
npm install
ddev artisan key:generate
ddev artisan migrate
ddev artisan db:seed --class=ServerSeeder
```

## Differences from the 5.x kit

The two branches run different stacks, so the kits are not interchangeable — the
project provisioning differs even though the sandbox plumbing is identical.

- MySQL 8.0 and PHP 8.2 here, Postgres 17 and PHP 8.4 on 5.x.
- The ddev project is `convoy4x`, so the app is at `https://convoy4x.ddev.site`.
That one has to differ: a 4.x and a 5.x sandbox otherwise fight over the same
ddev project name. The kit itself is still `convoy-dev` on both branches —
kits are referenced by path (`--kit .sbx/dev`), so there is nothing to collide.
The suggested *template* name is scoped, though, since the saved image bakes in
this branch's PHP and database versions and would otherwise clobber 5.x's.
- No separate test database. `tests/Pest.php` uses `DatabaseTransactions` rather
than `RefreshDatabase`, so the suite runs against the dev database and rolls its
own writes back — seeded dev data is visible to it and will fail any test that
asserts on a fleet-wide aggregate. `ddev artisan migrate:fresh` before a full run.
- Seeding is `ServerSeeder` (a location, a node, ten servers), and it needs no
Proxmox credentials.

## Boundaries

- **Secrets** live in the gitignored `.env`, mounted into the sandbox — never in a
kit.
- **Notifications** and any personal network setup come from global kits in the
operator's own dotfiles, injected automatically by their `sbx` wrapper; `.sbx/dev`
is project provisioning only. Multiple `--kit` refs compose, so they layer cleanly.
Loading
Loading