Files
LuaMicroservices/devices-api/db.lua
Christian van Dijk a6daab7961
Some checks failed
CI / Lint (push) Successful in 21s
CI / Helm Lint (push) Successful in 5s
CI / Build (push) Failing after 43s
CI / Test (push) Has been skipped
🧱 update CI workflow and remove alpinejs frontend files
2026-02-23 15:46:31 +01:00

124 lines
3.3 KiB
Lua

-- PostgreSQL connection pool using pgmoon
local pgmoon = require("pgmoon")
local DB_HOST = os.getenv("DB_HOST") or "localhost"
local DB_PORT = tonumber(os.getenv("DB_PORT")) or 5432
local DB_NAME = os.getenv("DB_NAME") or "handheld_devices"
local DB_USER = os.getenv("DB_USER") or "devices_user"
local DB_PASSWORD = os.getenv("DB_PASSWORD") or "devices_password"
local DB_POOL_SIZE = tonumber(os.getenv("DB_POOL_SIZE")) or 10
local DB_CONNECT_TIMEOUT_MS = tonumber(os.getenv("DB_CONNECT_TIMEOUT_MS")) or 5000
local DB_QUERY_TIMEOUT_MS = tonumber(os.getenv("DB_QUERY_TIMEOUT_MS")) or 10000
local config = {
host = DB_HOST,
port = tostring(DB_PORT),
database = DB_NAME,
user = DB_USER,
password = DB_PASSWORD,
socket_type = "luasocket",
}
local pool = {
available = {},
in_use = {},
max_size = DB_POOL_SIZE,
}
local function create_connection()
local pg = pgmoon.new(config)
pg:settimeout(DB_CONNECT_TIMEOUT_MS)
local ok, err = pg:connect()
if not ok then
return nil, err
end
pg:settimeout(DB_QUERY_TIMEOUT_MS)
return pg
end
local function get_connection()
local conn = table.remove(pool.available)
if conn then
table.insert(pool.in_use, conn)
return conn
end
if #pool.in_use >= pool.max_size then
return nil, "connection pool exhausted"
end
local pg, err = create_connection()
if not pg then
return nil, err
end
table.insert(pool.in_use, pg)
return pg
end
local function release_connection(conn)
for i, c in ipairs(pool.in_use) do
if c == conn then
table.remove(pool.in_use, i)
if #pool.available < pool.max_size then
table.insert(pool.available, conn)
else
pcall(function() conn:disconnect() end)
end
return
end
end
end
-- Execute with connection from pool; auto-release on return
local function with_connection(fn)
local conn, err = get_connection()
if not conn then
return nil, err
end
local ok, result, result_err = pcall(function()
return fn(conn)
end)
release_connection(conn)
if not ok then
return nil, result
end
return result, result_err
end
-- Retry with exponential backoff
local function with_retry(fn, max_attempts)
max_attempts = max_attempts or 3
local attempt = 0
local last_err
while attempt < max_attempts do
attempt = attempt + 1
local result, err = fn()
if result ~= nil or (err and not (err:match("connection") or err:match("timeout"))) then
return result, err
end
last_err = err
if attempt < max_attempts then
local delay = math.min(2 ^ attempt * 100, 5000)
require("socket").sleep(delay / 1000)
end
end
return nil, last_err
end
local function ping()
return with_connection(function(conn)
local res, err = conn:query("SELECT 1")
if res and type(res) == "table" and (res[1] or #res >= 1) then
return true
end
return nil, err or "ping failed"
end)
end
return {
config = config,
get_connection = get_connection,
release_connection = release_connection,
with_connection = with_connection,
with_retry = with_retry,
ping = ping,
}