FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Publisher pool cannot authenticate to password-protected Redis (NOAUTH in task-scheduler) — credentials dropped in registers.php and never used by utopia-php/queue · Issue #13554 · appwrite/appwrite · GitHub

Publisher pool cannot authenticate to password-protected Redis (NOAUTH in task-scheduler) — credentials dropped in registers.php and never used by utopia-php/queue #13554

Description

Summary

On Appwrite 2.0.0 (self-hosted) with an external Redis that requires a password, every publish through the publisher pool fails with NOAUTH Authentication required. Observed via the task-scheduler's hourly stats-resources task. The credentials are present in the container environment and are correct (verified directly against the Redis server); they are simply never passed to (or used by) the queue connection.

Environment

  • Appwrite 2.0.0 (self-hosted, Docker Compose)
  • Redis 7.4.7 external (own host, requirepass set)
  • _APP_REDIS_HOST, _APP_REDIS_PORT, _APP_REDIS_USER, _APP_REDIS_PASS set on all containers (verified inside the container with docker exec ... env | grep _APP_REDIS)

Observed behavior

appwrite-task-scheduler, every hour:

[StatsResources] Failed to publish stats resources message: NOAUTH Authentication required.
stats_resources_task · 207ms
  stats_resources_task.projects_queued 0
  stats_resources_task.projects_failed 1

Deterministic — persists across full stack restarts.

Additionally: the combined worker's queue consumers borrow the same publisher pool (app/worker.php line ~100: BrokerPool(publisher: $publisher, consumer: $publisher)), so on passworded Redis, messages pile up in the queue unconsumed as well — verify with LLEN utopia-queue.queue.v1-stats-resources.

Everything else that uses Redis works: realtime pub/sub authenticates and serves, the cache pool works, and queue produce/consume for table attribute creation works end to end when Redis has no password.

Root cause — two layers

Layer 1: app/init/registers.php (2.0.0) — the publisher pool drops the DSN credentials.
The fallback Redis DSN is built with user and pass:

$fallbackForRedis = 'redis_main=' . AppwriteURL::unparse([
    'scheme' => 'redis',
    'host' => System::getEnv('_APP_REDIS_HOST', 'redis'),
    'port' => System::getEnv('_APP_REDIS_PORT', '6379'),
    'user' => System::getEnv('_APP_REDIS_USER', ''),
    'pass' => System::getEnv('_APP_REDIS_PASS', ''),
]);

…but the publisher adapter constructs the connection with host and port only:

case 'publisher':
    return match ($dsn->getScheme()) {
        'redis' => (function () use ($dsn) {
            $connection = new Queue\Connection\Redis($dsn->getHost(), $dsn->getPort());
            return new Queue\Broker\Redis($connection, $connection);
        })(),
        default => null
    };

All other Redis pools (cache, pubsub, lock) go through the shared $resource() factory, which does pconnect + $redis->auth($dsnPass) — which is why those paths authenticate correctly and only the publisher fails.

Layer 2: utopia-php/queue Connection\Redis accepts $user/$password but never authenticates.
Current main of utopia-php/queue, src/Queue/Connection/Redis.php:

public function __construct(protected string $host, protected int $port = 6379,
    protected ?string $user = null, protected ?string $password = null,
    protected float $connectTimeout = -1, protected float $readTimeout = -1) {}

protected function getRedis(): \Redis
{
    // ...
    $redis = new \Redis();
    $redis->connect($this->host, $this->port, $connectTimeout);
    if ($this->readTimeout >= 0) {
        $redis->setOption(\Redis::OPT_READ_TIMEOUT, $this->readTimeout);
    }
    $this->redis = $redis;
    return $this->redis;
    // ...
}

$this->user and $this->password are never read; there is no auth() call anywhere in the class. Even if Appwrite passed them, the connection would still not authenticate.

Evidence it is not a configuration problem

  1. Credentials verified inside the running container (docker exec env): _APP_REDIS_PASS, _APP_REDIS_USER, _APP_REDIS_HOST, _APP_REDIS_PORT all present and correct.
  2. Direct protocol test from the same host: AUTH default <pass> → +OK; PING → +PONG; LPUSH/LPOP succeed. Two-argument AUTH form (used when _APP_REDIS_USER is set) also returns +OK.
  3. Realtime, cache, and lock pools authenticate against the same server with the same env — only the publisher pool fails.
  4. Survives full stack restarts; failure is deterministic (the code path never attempts auth).
  5. With a passwordless Redis, everything works — confirming the bug only manifests with authentication enabled.

Why default installs don't see this

The official docker-compose Redis service runs without requirepass and _APP_REDIS_PASS defaults to empty — the publisher's missing auth is invisible. The bug only manifests for self-hosters pointing at password-protected external Redis.

Suggested fix

utopia-php/queue — in getRedis(), after connect():

if ($this->password !== null && $this->password !== '') {
    $this->user
        ? $redis->auth([$this->user, $this->password])
        : $redis->auth($this->password);
}

appwrite — in registers.php, pass the DSN credentials to the publisher connection:

$connection = new Queue\Connection\Redis(
    $dsn->getHost(),
    $dsn->getPort(),
    $dsn->getUser() ?? null,
    $dsn->getPassword() ?? null
);

Impact

  • Hourly resource gauges (v1-stats-resources) are not published — Usage tab resource stats missing.
  • On passworded Redis, ALL queue messages published by the scheduler pile up unconsumed (scheduled functions, stats, etc.) since the worker's consumer also borrows the publisher pool.
  • Any other producer using the publisher pool against passworded Redis is affected the same way.

Related


Filed from a live deployment: Appwrite 2.0.0 on Coolify with external PostgreSQL/Redis/ClickHouse. Verified fix working in production: queue depth 2 → 0, gauges 0 → 210 after patching.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    api / realtimeFixes and upgrades for the Appwrite Realtime API.product / authFixes and upgrades for the Appwrite Auth / Users / Teams services.product / databasesFixes and upgrades for the Appwrite Database.product / functionsFixes and upgrades for the Appwrite Functions.product / self-hostedIssues only found when self-hosting Appwrite

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions


      Back | FazBrowse Home | New Git URL