Unknown directive "@live" in docker

Hi :wave:

I’m currently trying to deploy realtime with docker and running into the error Unknown directive "@live"

this is my docker-compose.dev.yml

version: "3.8"

services:
  redwood:
    build:
      context: .
      dockerfile: ./Dockerfile
      target: base
    command: >
      sh -c "yarn redwood prisma generate &&
             yarn redwood prisma migrate deploy &&
             yarn redwood prisma db seed &&
             yarn redwood dev"
    volumes:
      - .:/home/node/app
      - node_modules:/home/node/app/node_modules
    ports:
      - "8910:8910"
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgresql://redwood:redwood@db:5432/redwood
      - TEST_DATABASE_URL=postgresql://redwood:redwood@db:5432/redwood_test
      - NODE_ENV=development

  db:
    image: postgres:16-bookworm
    environment:
      POSTGRES_USER: redwood
      POSTGRES_PASSWORD: redwood
      POSTGRES_DB: redwood
    ports:
      - "5432:5432"
    volumes:
      - postgres:/var/lib/postgresql/data

  test-db:
    image: postgres:16-bookworm
    environment:
      POSTGRES_USER: redwood
      POSTGRES_PASSWORD: redwood
      POSTGRES_DB: redwood
    ports:
      - '5433:5432'
    volumes:
      - postgres-test:/var/lib/postgresql/data

  console:
    user: root
    build:
      context: .
      dockerfile: ./Dockerfile
      target: console
    tmpfs:
      - /tmp
    command: "true"
    environment:
      - DATABASE_URL=postgresql://redwood:redwood@db:5432/redwood
      - TEST_DATABASE_URL=postgresql://redwood:redwood@db:5432/redwood_test
    depends_on:
      - db

volumes:
  node_modules:
  postgres:
  postgres-test:

which works flawlessly with realtime liveQueries.

and this is my deploy docker-compose.prod.yml

version: "3.8"

services:
  web:
    build:
      context: .
      dockerfile: ./Dockerfile
      target: web_serve
    ports:
      - "8910:8910"
    depends_on:
      - api

  api:
    build:
      context: .
      dockerfile: ./Dockerfile
      target: api_serve
    ports:
      - "8911:8911"
    depends_on:
      - init
    environment:
      - DATABASE_URL=postgresql://redwood:redwood@db:5432/redwood

  init:
    build:
      context: .
      dockerfile: ./Dockerfile
      target: console
    command: >
      sh -c "yarn redwood prisma migrate deploy"
    depends_on:
      - db
    environment:
      - DATABASE_URL=postgresql://redwood:redwood@db:5432/redwood

  db:
    image: postgres:16-bookworm
    environment:
      POSTGRES_USER: redwood
      POSTGRES_PASSWORD: redwood
      POSTGRES_DB: redwood
    ports:
      - "5432:5432"

and lastly… this is my Dockerfile

# base
# ------------------------------------------------
FROM node:20-bookworm-slim as base

# We tried to make the Dockerfile as lean as possible. In some cases, that means we excluded a dependency your project needs.
# By far the most common is Python. If you're running into build errors because `python3` isn't available,
# uncomment the line below here and in other stages as necessary:
RUN apt-get update && apt-get install -y \
    openssl \
    # python3 make gcc \
    && rm -rf /var/lib/apt/lists/*

USER node
WORKDIR /home/node/app

COPY --chown=node:node .yarn/plugins .yarn/plugins
COPY --chown=node:node .yarn/releases .yarn/releases
COPY --chown=node:node .yarnrc.yml .
COPY --chown=node:node package.json .
COPY --chown=node:node api/package.json api/package.json
COPY --chown=node:node web/package.json web/package.json
COPY --chown=node:node yarn.lock .

RUN mkdir -p /home/node/.yarn/berry/index

RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
    --mount=type=cache,target=/home/node/.cache,uid=1000 \
    CI=1 yarn install

COPY --chown=node:node redwood.toml .
COPY --chown=node:node graphql.config.js .
COPY --chown=node:node .env.defaults .env.defaults

# api build
# ------------------------------------------------
FROM base as api_build

# If your api side build relies on build-time environment variables,
# specify them here as ARGs. (But don't put secrets in your Dockerfile!)
#
# ARG MY_BUILD_TIME_ENV_VAR

COPY --chown=node:node api api
RUN yarn redwood build api

# web prerender build
# ------------------------------------------------
FROM api_build as web_build_with_prerender

COPY --chown=node:node web web
RUN yarn redwood build web

# web build
# ------------------------------------------------
FROM base as web_build

COPY --chown=node:node web web
RUN yarn redwood build web --no-prerender

# serve api
# ------------------------------------------------
FROM node:20-bookworm-slim as api_serve

RUN apt-get update && apt-get install -y \
    openssl \
    # python3 make gcc \
    && rm -rf /var/lib/apt/lists/*

USER node
WORKDIR /home/node/app

COPY --chown=node:node .yarn/plugins .yarn/plugins
COPY --chown=node:node .yarn/releases .yarn/releases
COPY --chown=node:node .yarnrc.yml .
COPY --chown=node:node package.json .
COPY --chown=node:node api/package.json api/package.json
COPY --chown=node:node yarn.lock .

RUN mkdir -p /home/node/.yarn/berry/index

RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
    --mount=type=cache,target=/home/node/.cache,uid=1000 \
    CI=1 yarn workspaces focus api --production

COPY --chown=node:node redwood.toml .
COPY --chown=node:node graphql.config.js .
COPY --chown=node:node .env.defaults .env.defaults

COPY --chown=node:node --from=api_build /home/node/app/api/dist /home/node/app/api/dist
COPY --chown=node:node --from=api_build /home/node/app/api/db /home/node/app/api/db
COPY --chown=node:node --from=api_build /home/node/app/node_modules/.prisma /home/node/app/node_modules/.prisma

ENV NODE_ENV=production
CMD [ "node_modules/.bin/rw-server", "api", "--rootPath=/api" ]

# serve web
# ------------------------------------------------
FROM node:20-bookworm-slim as web_serve

USER node
WORKDIR /home/node/app

COPY --chown=node:node .yarn/plugins .yarn/plugins
COPY --chown=node:node .yarn/releases .yarn/releases
COPY --chown=node:node .yarnrc.yml .
COPY --chown=node:node package.json .
COPY --chown=node:node web/package.json web/
COPY --chown=node:node yarn.lock .

RUN mkdir -p /home/node/.yarn/berry/index

RUN --mount=type=cache,target=/home/node/.yarn/berry/cache,uid=1000 \
    --mount=type=cache,target=/home/node/.cache,uid=1000 \
    CI=1 yarn workspaces focus web --production

COPY --chown=node:node redwood.toml .
COPY --chown=node:node graphql.config.js .
COPY --chown=node:node .env.defaults .env.defaults

COPY --chown=node:node --from=web_build /home/node/app/web/dist /home/node/app/web/dist

ENV NODE_ENV=production
ENV API_PROXY_TARGET=http://api:8911

CMD "node_modules/.bin/rw-web-server" "--api-proxy-target" "$API_PROXY_TARGET"

# console
# ------------------------------------------------
FROM base as console

# To add more packages:
#
# ```
# USER root
#
# RUN apt-get update && apt-get install -y \
#     curl
#
# USER node
# ```

COPY --chown=node:node api api
COPY --chown=node:node web web
COPY --chown=node:node scripts scripts

RUN yarn redwood prisma generate

these files are all pretty standard. except the last line in the dockerfile to reuse the console target as an init container for db migrations.

I’v been using these files since the experimental days so I’m wondering if I’m missing anything here to make realtime work in docker containers.

Every help appreciated! :pray:

Hi @xmaxcooking did you setup real-time as shown here? Realtime | RedwoodJS Docs

The live directive is added automatically to the graphql schema and code gen based on the realtime config.

See the following code for more info: redwood/packages/realtime/src/graphql/plugins/useRedwoodRealtime.ts at ea82ca0154750a22a7710a76f89a122081e8f335 · redwoodjs/redwood · GitHub

Yes and everything works with the docker build target base and starting it with yarn redwood dev but switching to the target api_serve and web_serve doesn’t seem to work anymore on both sides.

import { clerkAuthDecoder as authDecoder } from '@redwoodjs/auth-clerk-api'
import { createGraphQLHandler } from '@redwoodjs/graphql-server'

import directives from 'src/directives/**/*.{js,ts}'
import sdls from 'src/graphql/**/*.sdl.{js,ts}'
import services from 'src/services/**/*.{js,ts}'

import { getCurrentUser } from 'src/lib/auth'
import { db } from 'src/lib/db'
import { realtime } from 'src/lib/realtime'
import { logger } from 'src/lib/logger'

export const handler = createGraphQLHandler({
  authDecoder,
  getCurrentUser,
  loggerConfig: {
    logger,
    options: {
      operationName: true,
      //query: false,
      //data: false,
      //tracing: false
    },
  },
  directives,
  sdls,
  services,
  realtime,
  cors: {
    origin: '*',
    credentials: true,
  },
  onException: () => {
    // Disconnect from your database with an unhandled exception.
    db.$disconnect()
  },
})

Is vite maybe doing some internal magic here which is missing in the rw-api/web-server? I honestly can’t tell.

Hi @xmaxcooking I’,m working to get your repo installed and hoping to reproduce.

I did run your app without docker via yarn rw dev and also serve and did see live queries working as expected. (as you noted)

I’ll be back later after getting the docker dev and production configured and investigate.

@xmaxcooking

Ok I was able to run docker compose -f ./docker-compose.dev.yml up ie DEV and saw live queries working in GraphQL playground and getting an update having added a new post via scaffold.

But then with docker compose -f ./docker-compose.prod.yml up aka prod I do see.

{
  "errors": [
    {
      "message": "Unknown directive \"@live\".",
      "locations": [
        {
          "line": 1,
          "column": 15
        }
      ]
    }
  ]
}

Thanks for this repo as I can see the behavior you described. Now to see why :slight_smile:

1 Like

@xmaxcooking OK - we have a solution!

Thanks to @Josh-Walker-GM we realized that in your setup, Docker (in production only) was never running the server file but rather just the plan vanilla api server.

What that meant was the the full GraphQL Server with the realtime plugin was never initialized so then realtime wasn’t configure which is why the @live query wasn’t recognized nor were subscriptions added to the schema.

A quick fix is to change your Dockerfile to run the server (and not the default api server):

# CMD [ "node_modules/.bin/rw-server", "api" ]
 CMD [ "./api/dist/server.js" ]

This step is documented, but it’s easily missed and in fact I did not even on a few reads.

Alternatively, you can tell your docket production yaml config to always run the server command by adding the same command:

version: "3.8"

services:
  api:
    build:
      context: .
      dockerfile: ./Dockerfile
      target: api_serve
    command: "./api/dist/server.js"
    ports:
      - "8911:8911"

Without it, it defaults to the Dockerfile one.

Please try one of those and let me know if it works – I was able to get live queries working again.

I’ll have a PR to clarify the docs and also add some comments in the Dockerfile and config to point to the change needed if running ing the server file.

Thanks for letting us know and helping us figure it out.

Thank you! That makes perfect sense. I was using docker way before the server file, so I completely missed that line. :heart:

Have a PR to help clarify since I also missed that necessary change.