cloudflare / workers-sdk

⛅️ Home to Wrangler, the CLI for Cloudflare Workers®
https://developers.cloudflare.com/workers/
Apache License 2.0
2.68k stars 701 forks source link

🐛 BUG: Connecting to Neon DB (via WebSockets) stopped working with wrangler 3.82.0 #7072

Open gourgouris opened 1 week ago

gourgouris commented 1 week ago

Which Cloudflare product(s) does this pertain to?

Wrangler

What version(s) of the tool(s) are you using?

wranger: 3.82.0, @neondatabase/serverless: ^0.10.1

What version of Node are you using?

20.18.0

What operating system and version are you using?

Win 11

Describe the Bug

Observed behavior

Running queries to a Neon db from a worker stopped working after upgrading to wrangler 3.82.0 A ws proxy is sitting in front of neon db, which forwards the requests to the underlying postgres db.

Expected behavior

Before upgrading to 3.82.0 (with 3.81.0), there were no issues.

Steps to reproduce

Below is a minimum reproducible example, with a docker-compose to setup an emulated neondb locally with 1 table to test.

npm create cloudflare@latest

wrangler.toml

#:schema node_modules/wrangler/config-schema.json
name = "blue-wave-e62a"
main = "src/index.ts"
compatibility_date = "2024-10-11"
compatibility_flags = ["nodejs_compat"]

src/index.ts

import { neonConfig, Pool } from "@neondatabase/serverless";
import { drizzle } from "drizzle-orm/neon-serverless";
import * as schema from "./schema";

export default {
    async fetch(request, env, ctx): Promise<Response> {
        console.log("before");
        await getDb().query.test.findFirst();
        console.log("after"); // hangs, never gets here
        return new Response('Hello World!');
    },
} satisfies ExportedHandler<Env>;

function getDb() {
    const dbClient = new Pool({ connectionString: "postgres://testdb:testdb@localhost:5442/testdb" });

        // necessary to make neon work locally, used to work fine.
    neonConfig.wsProxy = () => "127.0.0.1:5443/v1";
    neonConfig.useSecureWebSocket = false;
    neonConfig.pipelineTLS = false;
    neonConfig.pipelineConnect = false;

    return drizzle(dbClient, { schema, logger: true });
}

src/schema.ts

import { pgTable, text } from "drizzle-orm/pg-core";

export const test = pgTable("test", {
    name: text("name").notNull(),
});

package.json

{
  "name": "blue-wave-e62a",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "dev": "wrangler dev"
  },
  "devDependencies": {
    "typescript": "^5.5.2",
    "wrangler": "^3.82.0"
  },
  "dependencies": {
    "@neondatabase/serverless": "^0.10.1",
    "drizzle-orm": "^0.35.3"
  }
}

docker-compose.yml

name: test
services:
  postgres:
    container_name: test-pg
    image: postgres:17
    restart: unless-stopped
    ports: 
      - 5442:5432
    environment:
      POSTGRES_USER: testdb
      POSTGRES_PASSWORD: testdb
      POSTGRES_DB: testdb
      POSTGRES_HOST_AUTH_METHOD: trust
    volumes:
      - ./dump.sql:/docker-entrypoint-initdb.d/dump.sql:ro
      - type: tmpfs
        target: /var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -h postgres -U testdb -d testdb"]
      interval: 5s
      timeout: 1s
      retries: 3

  pg_proxy:
    container_name: test-pg_proxy
    image: ghcr.io/neondatabase/wsproxy:latest
    restart: unless-stopped
    environment:
      APPEND_PORT: postgres:5432
      ALLOW_ADDR_REGEX: ".*"
      LOG_TRAFFIC: true
      LOG_CONN_INFO: true
    ports:
      - 5443:80
    depends_on:
      - postgres
    healthcheck:
      test: ["CMD-SHELL", "exit 0"]
      interval: 5s
      timeout: 1s
      retries: 3

dump.sql

CREATE TABLE public.test (
    name text NOT NULL
);
ALTER TABLE public.test OWNER TO testdb;

run docker-compose up -d run npm run dev in another terminal run curl localhost:8787 it hangs

now try either

it works .. unfortunatelly removing nodejs_compat is not an option

Please provide a link to a minimal reproduction

No response

Please provide any relevant error logs

when running with log-level debug npm run dev -- --log-level debug I get this when it hangs:

[InspectorProxyWorker] RUNTIME INCOMING MESSAGE { id: 100000003, method: 'Network.enable', result: {} }                                                                                                  
before
[InspectorProxyWorker] RUNTIME INCOMING MESSAGE {                                                                                                                                                        
  method: 'Runtime.consoleAPICalled',                                                                                                                                                                    
  params: {                                                                                                                                                                                              
    type: 'log',
    args: [ [Object] ],
    executionContextId: 92388865,
    timestamp: 1729699107697,
    stackTrace: { callFrames: [Array] }
  }
}
Query: select "name" from "test" limit $1 -- params: [1]                                                                                                                                                 
[InspectorProxyWorker] RUNTIME INCOMING MESSAGE {                                                                                                                                                        
  method: 'Runtime.consoleAPICalled',                                                                                                                                                                    
  params: {                                                                                                                                                                                              
    type: 'log',
    args: [ [Object] ],
    executionContextId: 92388865,
    timestamp: 1729699107704,
    stackTrace: { callFrames: [Array] }
  }
}
[InspectorProxyWorker] RUNTIME INCOMING MESSAGE {                                                                                                                                                        
  method: 'Network.requestWillBeSent',                                                                                                                                                                   
  params: {                                                                                                                                                                                              
    requestId: '0',
    loaderId: '',
    request: {
      url: 'http://127.0.0.1:5443/v1',
      method: 'GET',
      headers: [Object],
      mixedContentType: 'blockable',
      initialPriority: 'VeryLow',
      referrerPolicy: 'unsafe-url',
      isLinkPreload: false
    },
    timestamp: 38247.84,
    wallTime: 1729699107.71,
    initiator: { type: 'script', stack: [Object], lineNumber: 0 },
    type: 'Fetch'
  }
}

I get exactly the same when i downgrade or remove nodejs_compat just until the point it used to hang.

bastiankistner commented 5 days ago

I can confirm that I experience the same issue.