Cloudflare WorkersからPostgreSQLに接続すると「write CONNECTION_ENDED」になった話
2024年12月10日 火曜日 09時00分Cloudflare WorkersからPostgres.jsを使って、PostgreSQLに接続する際に、エラーになりましたので、自分用のメモとして、残しておきます。
各ドキュメントのサンプルコード
Cloudflareのドキュメントは以下の通りです。
Connect to a PostgreSQL database with Cloudflare Workers · Cloudflare Workers docs
import postgres from "postgres";
export default {
async fetch(request, env, ctx): Promise<Response> {
const sql = postgres(env.DB_URL);
// Query the products table
const result = await sql`SELECT * FROM products;`;
// Return the result as JSON
const resp = new Response(JSON.stringify(result), {
headers: { "Content-Type": "application/json" },
});
return resp;
},
} satisfies ExportedHandler<Env>;
Postgres.jsのGitHubのコードは以下の通りです。
// db.js
import postgres from 'postgres'
const sql = postgres({ /* options */ }) // will use psql environment variables
export default sql
// users.js
import sql from './db.js'
async function getUsersOver(age) {
const users = await sql`
select
name,
age
from users
where age > ${ age }
`
// users = Result [{ name: "Walter", age: 80 }, { name: 'Murray', age: 68 }, ...]
return users
}
最初に書いたコード
以下のコードをデプロイしましたら、1回目のリクエスト時は成功しますが、数秒後に、改めてリクエストすると、エラーになりました。
// db.service.ts
import postgres from 'postgres';
export const sql = postgres(
{
host: 'db.example.com',
port: 5432,
database: 'my_database',
username: 'my_username',
password: 'my_password',
});
// getCustomerById.controller.ts
import {Context, Next} from "hono";
import {Customer} from "../../type/shared.type";
import {RowList} from "postgres";
import {sql} from "../../service/db.service";
export async function getCustomerByIdController(c: Context, next: Next): Promise<Response> {
try {
const customerId = c.req.param('customerId')
const customers: RowList<[Customer]> = await sql`
select *
from my_database.customer
where id = ${customerId};
`;
console.log(customers);
await sql.end();
return c.text(`ok`, 200)
} catch (error) {
console.error(error)
return c.text(`error`, 400)
}
}
// index.ts
import {Hono, Context, Next} from 'hono'
import {getCustomerByIdController} from "./controller/customer/getCustomerById.controller"
const app = new Hono<{ Bindings: Bindings }>()
app.get('/customer/:customerId', getCustomerByIdController)
export default app
確認するために、wrangler tailでログを確認しました。
wrangler tail <WORKER> [OPTIONS]
Commands - Wrangler · Cloudflare Workers docs
1回目のログ
OPTIONS https://api.example.com/customer/1 - Ok @ 2024/12/10 15:37:27
GET https://api.example.com/customer/1 - Ok @ 2024/12/10 15:37:27
(log) getCustomerByIdController
(log) [
{
name: 'すずき',
created_at: '2024-12-05T07:00:28.441Z',
updated_at: '2024-12-09T11:42:24.947Z'
}
]
連続した2回目以降のログ
OPTIONS https://api.example.com/customer/1 - Ok @ 2024/12/10 15:37:27
GET https://api.example.com/customer/1 - Ok @ 2024/12/10 15:37:27
(log) getCustomerByIdController
(error) Error: write CONNECTION_ENDED api.example.com:5432
私の力が足りないので、修正内容が合っているか自信はありませんが、コードの一部を修正しました。
詳しい方がいらっしゃいましたら、原因や、もっと良い書き方を教えて頂ければと思います。
修正したコード
// db.service.ts
import postgres from 'postgres';
import {Context} from "hono";
export function createSql(c: Context) {
return postgres(
{
host: c.env.DB_HOST,
port: c.env.DB_PORT,
database: c.env.DB_DATABASE,
username: c.env.DB_USERNAME,
password: c.env.DB_PASSWORD,
});
}
// getCustomerById.controller.ts
import {Context, Next} from "hono";
import {Customer} from "../../type/shared.type";
import {RowList} from "postgres";
import {createSql} from "../../service/db.service";
export async function getCustomerByIdController(c: Context, next: Next): Promise<Response> {
try {
const customerId = c.req.param('customerId')
const sql = createSql(c)
const customers: RowList<[Customer]> = await sql`
select *
from my_database.customer
where id = ${customerId};
`;
console.log(customers);
await sql.end();
return c.text(`ok`, 200)
} catch (error) {
console.error(error)
return c.text(`error`, 400)
}
}