feat: page, hash and rootline caches in Redis again, as on TYPO3 10
Since every page view goes through TYPO3 13, the page cache is on the hot path; TYPO3 10 kept it in Redis, TYPO3 13 had it in MySQL. Same socket and options as TYPO3 10, but databases 3-5 instead of 0-2, which may still hold TYPO3 10 entries in a format TYPO3 13 must not read. DDEV gets the redis add-on for the same setup locally. Without a Redis connection the backend logs an alert and misses, so pages still render (slower); a missing PHP redis extension, however, fails hard. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
520feb003f
commit
df3d823de4
7 files changed
+269
No files matched your search
@@ -0,0 +1,38 @@
|
|||||||
|
name: redis
|
||||||
|
repository: ddev/ddev-redis
|
||||||
|
version: v3.0.0
|
||||||
|
install_date: "2026-10-24T18:50:06+02:00"
|
||||||
|
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
|
||||||
Executable
+136
@@ -0,0 +1,136 @@
|
|||||||
|
#!/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
|
||||||
|
|
||||||
|
# Keep in sync with the default image in docker-compose.redis.yaml
|
||||||
|
DEFAULT_REDIS_DOCKER_IMAGE="redis:8"
|
||||||
|
|
||||||
|
REDIS_DOCKER_IMAGE=${1:-}
|
||||||
|
REDIS_CONFIG=${2:-}
|
||||||
|
|
||||||
|
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 ${DEFAULT_REDIS_DOCKER_IMAGE}
|
||||||
|
redis-alpine ${DEFAULT_REDIS_DOCKER_IMAGE}-alpine
|
||||||
|
valkey valkey/valkey:9
|
||||||
|
valkey-alpine valkey/valkey:9-alpine
|
||||||
|
|
||||||
|
Custom backend:
|
||||||
|
You can specify any Docker image, e.g.:
|
||||||
|
ddev redis-backend redis:7
|
||||||
|
|
||||||
|
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:8.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" != "$DEFAULT_REDIS_DOCKER_IMAGE" ]] && ddev dotenv set .ddev/.env.redis --redis-docker-image="$REDIS_DOCKER_IMAGE"
|
||||||
|
# Reinstall the same add-on version that is installed now
|
||||||
|
local repo version flags=()
|
||||||
|
IFS='|' read -r repo version < <(ddev add-on list --installed -j 2>/dev/null | docker run -i --rm ddev/ddev-utilities jq -r '.raw[] | select(.Name=="redis") | "\(.Repository // "")|\(.Version // "")"' 2>/dev/null)
|
||||||
|
case "$version" in
|
||||||
|
# installed from a local directory
|
||||||
|
"") ;;
|
||||||
|
pr-*) flags=(--pr "${version#pr-}") ;;
|
||||||
|
v[0-9]*) flags=(--version "$version") ;;
|
||||||
|
# the default branch name, e.g. "main"
|
||||||
|
*) flags=(--default-branch) ;;
|
||||||
|
esac
|
||||||
|
ddev add-on get "${repo:-ddev/ddev-redis}" "${flags[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# "ddev add-on get" overwrites this file while it is running, so keep the main flow
|
||||||
|
# in a block, which bash reads completely before running it
|
||||||
|
{
|
||||||
|
case "$REDIS_DOCKER_IMAGE" in
|
||||||
|
redis)
|
||||||
|
REDIS_DOCKER_IMAGE="$DEFAULT_REDIS_DOCKER_IMAGE"
|
||||||
|
;;
|
||||||
|
redis-alpine)
|
||||||
|
REDIS_DOCKER_IMAGE="${DEFAULT_REDIS_DOCKER_IMAGE}-alpine"
|
||||||
|
;;
|
||||||
|
valkey)
|
||||||
|
REDIS_DOCKER_IMAGE="valkey/valkey:9"
|
||||||
|
REDIS_HOSTNAME="valkey"
|
||||||
|
;;
|
||||||
|
valkey-alpine)
|
||||||
|
REDIS_DOCKER_IMAGE="valkey/valkey:9-alpine"
|
||||||
|
REDIS_HOSTNAME="valkey"
|
||||||
|
;;
|
||||||
|
""|--help|-h)
|
||||||
|
show_help
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# 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'"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
Executable
+13
@@ -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
|
||||||
Executable
+12
@@ -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
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#ddev-generated
|
||||||
|
services:
|
||||||
|
redis:
|
||||||
|
container_name: ddev-${DDEV_SITENAME}-redis
|
||||||
|
image: ${REDIS_DOCKER_IMAGE:-redis:8}
|
||||||
|
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:8}
|
||||||
|
describe-info: |
|
||||||
|
Pass: <none>
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
redis:
|
||||||
@@ -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 ""
|
||||||
@@ -64,6 +64,36 @@ if (getenv('IS_DDEV_PROJECT') == 'true') {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Redis caches as on TYPO3 10, but in databases 3-5: 0-2 may still hold TYPO3 10 entries. Without a
|
||||||
|
// connection the backend only logs an alert and every lookup is a miss, so pages still render.
|
||||||
|
$redisOptions = getenv('IS_DDEV_PROJECT') == 'true'
|
||||||
|
? ['hostname' => 'redis', 'port' => 6379]
|
||||||
|
: ['hostname' => '/run/redis_eptypo3/redis.sock', 'port' => 0];
|
||||||
|
$redisOptions['connectionTimeout'] = 2;
|
||||||
|
|
||||||
|
// These replace the definitions from settings.php wholesale, so 'groups' and the compression and
|
||||||
|
// lifetime options have to be repeated here. Each cache has its own database: RedisBackend::flush()
|
||||||
|
// issues FLUSHDB.
|
||||||
|
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['pages'] = [
|
||||||
|
'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class,
|
||||||
|
'backend' => \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class,
|
||||||
|
'options' => $redisOptions + ['database' => 3, 'compression' => true],
|
||||||
|
'groups' => ['pages'],
|
||||||
|
];
|
||||||
|
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['hash'] = [
|
||||||
|
'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class,
|
||||||
|
'backend' => \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class,
|
||||||
|
'options' => $redisOptions + ['database' => 4],
|
||||||
|
'groups' => ['pages'],
|
||||||
|
];
|
||||||
|
$GLOBALS['TYPO3_CONF_VARS']['SYS']['caching']['cacheConfigurations']['rootline'] = [
|
||||||
|
'frontend' => \TYPO3\CMS\Core\Cache\Frontend\VariableFrontend::class,
|
||||||
|
'backend' => \TYPO3\CMS\Core\Cache\Backend\RedisBackend::class,
|
||||||
|
'options' => $redisOptions + ['database' => 5, 'compression' => true, 'defaultLifetime' => 2592000],
|
||||||
|
'groups' => ['pages'],
|
||||||
|
];
|
||||||
|
unset($redisOptions);
|
||||||
|
|
||||||
// Deployer creates an empty secrets.php if none exists yet: only an array counts
|
// Deployer creates an empty secrets.php if none exists yet: only an array counts
|
||||||
$secrets = is_file(__DIR__ . '/secrets.php') ? require __DIR__ . '/secrets.php' : null;
|
$secrets = is_file(__DIR__ . '/secrets.php') ? require __DIR__ . '/secrets.php' : null;
|
||||||
if (is_array($secrets)) {
|
if (is_array($secrets)) {
|
||||||
|
|||||||
Reference in new issue
Block a user