Add Russian inline comments
This commit is contained in:
parent
29206538ef
commit
a5493c7375
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
Consumes CRUD messages from RabbitMQ and writes to Postgres.
|
Consumes CRUD messages from RabbitMQ and writes to Postgres.
|
||||||
|
|
||||||
|
Комментарий: воркер специально пишет в таблицу демо и не хранит собственное состояние, кроме метрик в памяти.
|
||||||
|
|
||||||
## Environment variables
|
## Environment variables
|
||||||
|
|
||||||
RabbitMQ:
|
RabbitMQ:
|
||||||
@ -20,3 +22,5 @@ Postgres:
|
|||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
Health endpoint: `/healthz`.
|
Health endpoint: `/healthz`.
|
||||||
|
|
||||||
|
HTML-страница со статусом доступна на `/`.
|
||||||
|
|||||||
13
server.js
13
server.js
@ -2,12 +2,14 @@ const http = require("http");
|
|||||||
const amqp = require("amqplib");
|
const amqp = require("amqplib");
|
||||||
const { Pool } = require("pg");
|
const { Pool } = require("pg");
|
||||||
|
|
||||||
|
// Состояние процесса для /healthz и статуса в UI.
|
||||||
const status = {
|
const status = {
|
||||||
state: "starting",
|
state: "starting",
|
||||||
error: "",
|
error: "",
|
||||||
lastSuccess: "",
|
lastSuccess: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Метрики обработки сообщений (показываются на HTML-странице).
|
||||||
const metrics = {
|
const metrics = {
|
||||||
processed: 0,
|
processed: 0,
|
||||||
failed: 0,
|
failed: 0,
|
||||||
@ -16,6 +18,7 @@ const metrics = {
|
|||||||
lastAction: "",
|
lastAction: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Унифицированное обновление состояния.
|
||||||
function setStatus(state, error) {
|
function setStatus(state, error) {
|
||||||
status.state = state;
|
status.state = state;
|
||||||
status.error = error || "";
|
status.error = error || "";
|
||||||
@ -24,6 +27,7 @@ function setStatus(state, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTML-страница со статусом и счетчиками.
|
||||||
function renderStatusPage() {
|
function renderStatusPage() {
|
||||||
const queueName = (process.env.RABBIT_QUEUES || "crud_queue").split(",")[0] || "crud_queue";
|
const queueName = (process.env.RABBIT_QUEUES || "crud_queue").split(",")[0] || "crud_queue";
|
||||||
const tableName = process.env.PG_TABLE || "rabbit_messages";
|
const tableName = process.env.PG_TABLE || "rabbit_messages";
|
||||||
@ -80,6 +84,7 @@ function renderStatusPage() {
|
|||||||
</html>`;
|
</html>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Подготовка конфигурации PG (DATABASE_URL имеет приоритет).
|
||||||
function buildPgConfig() {
|
function buildPgConfig() {
|
||||||
if (process.env.DATABASE_URL) {
|
if (process.env.DATABASE_URL) {
|
||||||
return {
|
return {
|
||||||
@ -98,6 +103,7 @@ function buildPgConfig() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Собираем AMQP URL из переменных окружения.
|
||||||
function buildAmqpUrl() {
|
function buildAmqpUrl() {
|
||||||
if (process.env.AMQP_URL) {
|
if (process.env.AMQP_URL) {
|
||||||
return process.env.AMQP_URL;
|
return process.env.AMQP_URL;
|
||||||
@ -115,12 +121,14 @@ function buildAmqpUrl() {
|
|||||||
|
|
||||||
const pool = new Pool(buildPgConfig());
|
const pool = new Pool(buildPgConfig());
|
||||||
|
|
||||||
|
// Минимальная таблица для демо, если БД пустая.
|
||||||
async function ensureTable(table) {
|
async function ensureTable(table) {
|
||||||
await pool.query(
|
await pool.query(
|
||||||
`CREATE TABLE IF NOT EXISTS ${table} (id SERIAL PRIMARY KEY, test_data TEXT, created_at TIMESTAMP DEFAULT NOW())`
|
`CREATE TABLE IF NOT EXISTS ${table} (id SERIAL PRIMARY KEY, test_data TEXT, created_at TIMESTAMP DEFAULT NOW())`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Парсим JSON, нормализуем ключи, иначе считаем текстом.
|
||||||
function parseMessage(buffer) {
|
function parseMessage(buffer) {
|
||||||
const body = buffer.toString("utf8");
|
const body = buffer.toString("utf8");
|
||||||
try {
|
try {
|
||||||
@ -143,6 +151,7 @@ function parseMessage(buffer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CRUD-операции по сообщению.
|
||||||
async function handleMessage(table, msg) {
|
async function handleMessage(table, msg) {
|
||||||
const action = (msg.action || "create").toLowerCase();
|
const action = (msg.action || "create").toLowerCase();
|
||||||
if (action === "create") {
|
if (action === "create") {
|
||||||
@ -167,6 +176,7 @@ async function handleMessage(table, msg) {
|
|||||||
throw new Error("invalid action");
|
throw new Error("invalid action");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Небольшой HTTP-сервер для /healthz и HTML-статуса.
|
||||||
function startHttpServer() {
|
function startHttpServer() {
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
const server = http.createServer((req, res) => {
|
const server = http.createServer((req, res) => {
|
||||||
@ -183,6 +193,7 @@ function startHttpServer() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Основной цикл: подключение к RabbitMQ и обработка сообщений.
|
||||||
async function consumeLoop() {
|
async function consumeLoop() {
|
||||||
const table = process.env.PG_TABLE || "rabbit_messages";
|
const table = process.env.PG_TABLE || "rabbit_messages";
|
||||||
const queueName = (process.env.RABBIT_QUEUES || "crud_queue")
|
const queueName = (process.env.RABBIT_QUEUES || "crud_queue")
|
||||||
@ -193,6 +204,7 @@ async function consumeLoop() {
|
|||||||
const prefetch = Number(process.env.RABBIT_PREFETCH || "1");
|
const prefetch = Number(process.env.RABBIT_PREFETCH || "1");
|
||||||
const requeueOnError = String(process.env.REQUEUE_ON_ERROR || "true").toLowerCase() === "true";
|
const requeueOnError = String(process.env.REQUEUE_ON_ERROR || "true").toLowerCase() === "true";
|
||||||
|
|
||||||
|
// Гарантируем наличие таблицы перед стартом консьюмера.
|
||||||
await ensureTable(table);
|
await ensureTable(table);
|
||||||
|
|
||||||
let backoffMs = 2000;
|
let backoffMs = 2000;
|
||||||
@ -206,6 +218,7 @@ async function consumeLoop() {
|
|||||||
|
|
||||||
setStatus("running", "");
|
setStatus("running", "");
|
||||||
|
|
||||||
|
// Обрабатываем сообщения и фиксируем успех/ошибки.
|
||||||
channel.consume(queueName, async (msg) => {
|
channel.consume(queueName, async (msg) => {
|
||||||
if (!msg) {
|
if (!msg) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user