surrealdb/surrealdb.js

Bug: Using docker compose networking causes TypeError: t.mask is not a function or connection to hang when running .wait() or .query()

NexVeridian opened this issue ยท 2 comments

Describe the bug

When using next.js 14.1.0 within a docker container and docker surrealdb/surrealdb:latest-dev

using a docker url name

db.connect("ws://surrealdb:8000/rpc");

Docker compose file

# .env
DB_URL_PORT=surrealdb:8000
DB_USER=root
DB_PASSWORD=root
version: "3"
services:
    nextjs:
        build: .
        env_file:
            - .env
        ports:
            - 3000:3000
        depends_on:
            - surrealdb
        networks:
            - surrealdb-network

    surrealdb:
        container_name: surrealdb
        image: surrealdb/surrealdb:latest-dev
        env_file:
            - .env
        entrypoint:
            - /surreal
            - start
            - --user
            - $DB_USER
            - --pass
            - $DB_PASSWORD
            - file:/data/surrealdb
        restart: always
        ports:
            - 8000:8000
        volumes:
            - ./data:/data
        networks:
            - surrealdb-network

volumes:
    data:

networks:
    surrealdb-network:

causes the following error when running npm run build CMD ["node", "server.js"], from within the next.js docker

TypeError: t.mask is not a function
    at e.exports.mask (/app/.next/server/chunks/235.js:1:59645)
    at h.frame (/app/.next/server/chunks/235.js:1:78447)
    at h.send (/app/.next/server/chunks/235.js:1:80497)
    at L.send (/app/.next/server/chunks/235.js:2:9182)
    at o.send (/app/.next/server/chunks/235.js:2:16756)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

docker file

# https://nextjs.org/docs/pages/building-your-application/deploying#docker-image
FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
ENV NEXT_TELEMETRY_DISABLED 1

# RUN yarn build
# If using npm comment out above and use below instead
RUN npm install
RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]

Or causes the connection to hang when using CMD ["npm ", "run", "dev"] from within the next.js docker file

docker file

# https://nextjs.org/docs/pages/building-your-application/deploying#docker-image
FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
ENV NEXT_TELEMETRY_DISABLED 1

# RUN yarn build
# If using npm comment out above and use below instead
RUN npm install
RUN npm run build

CMD ["npm ", "run", "dev"] 

Other notes

  • For both docker files there are no errors in the surrealdb docker container
  • Running next.js not in docker, and connect to the surrealdb docker container with 0.0.0.0:8000, works correctly
  • Using the rust sdk with a identical setup works correctly, with rust and surrealdb both in a docker container, connected with a docker compose network
    let db = Surreal::new::<Ws>("surrealdb:8000".as_str()).await?;

Steps to reproduce

run this with the docker compose file from above

import { Surreal } from "surrealdb.js";
db.connect("ws://surrealdb:8000/rpc", {
      namespace: "url",
      database: "url",
      auth: {
        username: root,
        password: root,
      },
    }
console.log(db);
let res = await db.query(`
    select * from test 
    `);

For a runnable example see

https://github.com/NexVeridian/next-url-shortener
at this route http://localhost:3000/stats

and look at these two code file, which is also the same as the above code

https://github.com/NexVeridian/next-url-shortener/blob/main/src/components/db-utils.tsx
https://github.com/NexVeridian/next-url-shortener/blob/main/src/app/stats/db.tsx

Full logs with console.log(db) before the query

Attaching to nextjs-1, surrealdb
surrealdb  | 
surrealdb  |  .d8888b.                                             888 8888888b.  888888b.
surrealdb  | d88P  Y88b                                            888 888  'Y88b 888  '88b
surrealdb  | Y88b.                                                 888 888    888 888  .88P
surrealdb  |  'Y888b.   888  888 888d888 888d888  .d88b.   8888b.  888 888    888 8888888K.
surrealdb  |     'Y88b. 888  888 888P'   888P'   d8P  Y8b     '88b 888 888    888 888  'Y88b
surrealdb  |       '888 888  888 888     888     88888888 .d888888 888 888    888 888    
888
surrealdb  | Y88b  d88P Y88b 888 888     888     Y8b.     888  888 888 888  .d88P 888   d88P
surrealdb  |  'Y8888P'   'Y88888 888     888      'Y8888  'Y888888 888 8888888P'  8888888P'
surrealdb  | 
surrealdb  | 
surrealdb  | 2024-02-18T14:53:16.757212Z  INFO surreal::env: Running 1.2.1 for linux on x86_64
surrealdb  | 2024-02-18T14:53:16.757245Z  WARN surreal::dbs: โŒ๐Ÿ”’ IMPORTANT: Authenticatio
n is disabled. This is not recommended for production use. ๐Ÿ”’โŒ
surrealdb  | 2024-02-18T14:53:16.757258Z  INFO surrealdb_core::kvs::ds: Starting kvs store at file:///data/surrealdb
surrealdb  | 2024-02-18T14:53:17.308290Z  INFO surrealdb_core::kvs::ds: Started kvs store at file:///data/surrealdb
surrealdb  | 2024-02-18T14:53:17.310273Z  WARN surrealdb_core::kvs::ds: Credentials were 
provided, but existing root users were found. The root user 'root' will not be created   
surrealdb  | 2024-02-18T14:53:17.310287Z  WARN surrealdb_core::kvs::ds: Consider removing the --user and --pass arguments from the server start command
surrealdb  | 2024-02-18T14:53:17.310295Z  INFO surrealdb::node: Started node agent       
surrealdb  | 2024-02-18T14:53:17.312579Z  INFO surrealdb::net: Started web server on 0.0.0.0:8000
nextjs-1   |    โ–ฒ Next.js 14.1.0
nextjs-1   |    - Local:        http://a608860dff66:3000
nextjs-1   |    - Network:      http://172.21.0.3:3000
nextjs-1   | 
nextjs-1   |  โœ“ Ready in 119ms
nextjs-1   | l {
nextjs-1   |   socket: o {
nextjs-1   |     url: 'ws://surrealdb:8000/rpc',
nextjs-1   |     hooks: {
nextjs-1   |       onConnect: [AsyncFunction: onConnect],
nextjs-1   |       onClose: [Function: onClose],
nextjs-1   |       onError: undefined
nextjs-1   |     },
nextjs-1   |     ws: L {
nextjs-1   |       _events: [Object: null prototype],
nextjs-1   |       _eventsCount: 4,
nextjs-1   |       _maxListeners: undefined,
nextjs-1   |       _binaryType: 'nodebuffer',
nextjs-1   |       _closeCode: 1006,
nextjs-1   |       _closeFrameReceived: false,
nextjs-1   |       _closeFrameSent: false,
nextjs-1   |       _closeMessage: <Buffer >,
nextjs-1   |       _closeTimer: null,
nextjs-1   |       _extensions: {},
nextjs-1   |       _paused: false,
nextjs-1   |       _protocol: '',
nextjs-1   |       _readyState: 0,
nextjs-1   |       _receiver: null,
nextjs-1   |       _sender: null,
nextjs-1   |       _socket: null,
nextjs-1   |       _bufferedAmount: 0,
nextjs-1   |       _isServer: false,
nextjs-1   |       _redirects: 0,
nextjs-1   |       _autoPong: true,
nextjs-1   |       _url: 'ws://surrealdb:8000/rpc',
nextjs-1   |       _req: [ClientRequest],
nextjs-1   |       [Symbol(shapeMode)]: false,
nextjs-1   |       [Symbol(kCapture)]: false
nextjs-1   |     },
nextjs-1   |     status: 1,
nextjs-1   |     queue: {},
nextjs-1   |     liveQueue: {},
nextjs-1   |     unprocessedLiveResponses: {},
nextjs-1   |     ready: Promise {
nextjs-1   |       <pending>,
nextjs-1   |       [Symbol(async_id_symbol)]: 157,
nextjs-1   |       [Symbol(trigger_async_id_symbol)]: 142,
nextjs-1   |       [Symbol(kResourceStore)]: [Object],
nextjs-1   |       [Symbol(kResourceStore)]: [Object],
nextjs-1   |       [Symbol(kResourceStore)]: [Object]
nextjs-1   |     },
nextjs-1   |     closed: Promise {
nextjs-1   |       <pending>,
nextjs-1   |       [Symbol(async_id_symbol)]: 151,
nextjs-1   |       [Symbol(trigger_async_id_symbol)]: 142,
nextjs-1   |       [Symbol(kResourceStore)]: [Object],
nextjs-1   |       [Symbol(kResourceStore)]: [Object],
nextjs-1   |       [Symbol(kResourceStore)]: [Object]
nextjs-1   |     },
nextjs-1   |     resolveClosed: [Function (anonymous)],
nextjs-1   |     socketClosureReason: { '1000': 'CLOSE_NORMAL' }
nextjs-1   |   },
nextjs-1   |   pinger: n { pinger: undefined, interval: 30000 },
nextjs-1   |   connection: {
nextjs-1   |     auth: { username: 'root', password: 'root' },
nextjs-1   |     namespace: 'url',
nextjs-1   |     database: 'url'
nextjs-1   |   },
nextjs-1   |   ready: Promise {
nextjs-1   |     <pending>,
nextjs-1   |     [Symbol(async_id_symbol)]: 149,
nextjs-1   |     [Symbol(trigger_async_id_symbol)]: 142,
nextjs-1   |     [Symbol(kResourceStore)]: {
nextjs-1   |       headers: [Getter],
nextjs-1   |       cookies: [Getter],
nextjs-1   |       mutableCookies: [Getter],
nextjs-1   |       draftMode: [Getter]
nextjs-1   |     },
nextjs-1   |     [Symbol(kResourceStore)]: {
nextjs-1   |       isStaticGeneration: false,
nextjs-1   |       urlPathname: '/stats',
nextjs-1   |       pagePath: '/stats/page',
nextjs-1   |       incrementalCache: [IncrementalCache],
nextjs-1   |       isRevalidate: true,
nextjs-1   |       isPrerendering: undefined,
nextjs-1   |       fetchCache: 'default-no-store',
nextjs-1   |       isOnDemandRevalidate: false,
nextjs-1   |       isDraftMode: false,
nextjs-1   |       postpone: undefined,
nextjs-1   |       fetchMetrics: []
nextjs-1   |     },
nextjs-1   |     [Symbol(kResourceStore)]: { isAction: true }
nextjs-1   |   },
nextjs-1   |   resolveReady: [Function (anonymous)],
nextjs-1   |   rejectReady: [Function (anonymous)],
nextjs-1   |   strategy: 'ws',
nextjs-1   |   hooks: {}
nextjs-1   | }
nextjs-1   | TypeError: t.mask is not a function
nextjs-1   |     at e.exports.mask (/app/.next/server/chunks/235.js:1:59645)
nextjs-1   |     at h.frame (/app/.next/server/chunks/235.js:1:78447)
nextjs-1   |     at h.send (/app/.next/server/chunks/235.js:1:80497)
nextjs-1   |     at L.send (/app/.next/server/chunks/235.js:2:9182)
nextjs-1   |     at o.send (/app/.next/server/chunks/235.js:2:16756)
nextjs-1   |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

db.query causes the TypeError: t.mask is not a function, db.create is ok

Expected behaviour

The query should run

SurrealDB version

1.2.1, docker surrealdb/surrealdb:latest-dev

SurrealDB.js version

0.11.0

Contact Details

nexveridian@gmail.com

Is there an existing issue for this?

  • I have searched the existing issues

Code of Conduct

  • I agree to follow this project's Code of Conduct

Hey @NexVeridian, it is quite possible that the docker image used for building nextjs ships an old version of NodeJS out of the box, which probably lacks certain functionality, and which is likely different from the version of NodeJS installed on your system. I've never really tested it, but my guess would be that anything above NodeJS v16 will work, but while you're at it you might aswell set it to node 18 or 20 ๐Ÿ˜ƒ

I think I have an update to date version
FROM node:20-alpine AS base

I just swapped it to FROM node:20-bookworm AS base
both have the same TypeError: t.mask is not a function as above

here is the full docker file, same as the one from the next.js docs

# https://nextjs.org/docs/pages/building-your-application/deploying#docker-image
FROM node:20-alpine AS base

# Install dependencies only when needed
FROM base AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat
WORKDIR /app

# Install dependencies based on the preferred package manager
COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* ./
RUN \
  if [ -f yarn.lock ]; then yarn --frozen-lockfile; \
  elif [ -f package-lock.json ]; then npm ci; \
  elif [ -f pnpm-lock.yaml ]; then yarn global add pnpm && pnpm i --frozen-lockfile; \
  else echo "Lockfile not found." && exit 1; \
  fi


# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
ENV NEXT_TELEMETRY_DISABLED 1

# RUN yarn build
# If using npm comment out above and use below instead
RUN npm install
RUN npm run build

# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app

ENV NODE_ENV production
# Uncomment the following line in case you want to disable telemetry during runtime.
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

# COPY --from=builder /app/public ./public

# Automatically leverage output traces to reduce image size
# https://nextjs.org/docs/advanced-features/output-file-tracing
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["node", "server.js"]