From 0e586c04b805b99aa1b8495be38cc225398a8647 Mon Sep 17 00:00:00 2001 From: Kuchizu <70284260+Kuchizu@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:04:27 +0300 Subject: [PATCH 1/2] Cap Mongo connection pools and index dailyEvents by groupHash (#659) * Cap Mongo connection pools and set appName per client * Add groupHash index to dailyEvents of new projects * Bump version up to 1.5.4 * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Bump version up to 1.5.5 * trigger ci --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- package.json | 2 +- src/mongo.ts | 15 +++++++++++++-- src/resolvers/project.js | 7 +++++++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 5097becd..674c52be 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hawk.api", - "version": "1.5.4", + "version": "1.5.5", "main": "index.ts", "license": "BUSL-1.1", "scripts": { diff --git a/src/mongo.ts b/src/mongo.ts index 60a2d5ff..9202b50c 100644 --- a/src/mongo.ts +++ b/src/mongo.ts @@ -7,12 +7,23 @@ const eventsDBUrl = process.env.MONGO_EVENTS_DB_URL || 'mongodb://localhost:2701 const reconnectTries = Number(process.env.MONGO_RECONNECT_TRIES) || 60; const reconnectInterval = Number(process.env.MONGO_RECONNECT_INTERVAL) || 1000; +const maxPoolSizeRaw = process.env.MONGO_MAX_POOL_SIZE; +const maxPoolSize = maxPoolSizeRaw !== undefined && Number.isFinite(Number(maxPoolSizeRaw)) + ? Number(maxPoolSizeRaw) + : 30; /** * serverSelectionTimeoutMS bounds how long an op waits for an available * server — without it queries hang forever during an outage. + * + * maxPoolSize caps sockets per client (driver default 100 lets API replicas + * alone exhaust the server-side 1024 limit); maxIdleTimeMS closes sockets + * left idle after spikes (default 0 keeps them forever). */ -const connectionConfig: MongoClientOptions = withMongoMetrics({ +const connectionConfig = (appName: string): MongoClientOptions => withMongoMetrics({ + appName, + maxPoolSize, + maxIdleTimeMS: 60000, serverSelectionTimeoutMS: 10000, socketTimeoutMS: 45000, retryWrites: true, @@ -77,7 +88,7 @@ async function connectWithRetry(name: string, url: string): Promise let lastError = 'unknown error'; for (let attempt = 1; attempt <= reconnectTries; attempt++) { - const client = new MongoClient(url, connectionConfig); + const client = new MongoClient(url, connectionConfig(`hawk-api-${name}`)); try { await client.connect(); diff --git a/src/resolvers/project.js b/src/resolvers/project.js index 18da81f3..7e4bf7fe 100644 --- a/src/resolvers/project.js +++ b/src/resolvers/project.js @@ -20,6 +20,7 @@ const EVENTS_PAYLOAD_RELEASE_INDEX_NAME = 'payloadRelease'; const GROUPING_TIMESTAMP_INDEX_NAME = 'groupingTimestamp'; const GROUPING_TIMESTAMP_AND_LAST_REPETITION_TIME_AND_ID_INDEX_NAME = 'groupingTimestampAndLastRepetitionTimeAndId'; const GROUPING_TIMESTAMP_AND_GROUP_HASH_INDEX_NAME = 'groupingTimestampAndGroupHash'; +const DAILY_EVENTS_GROUP_HASH_INDEX_NAME = 'groupHash'; const MAX_SEARCH_QUERY_LENGTH = 50; const FALLBACK_EVENT_TITLE = 'Unknown'; @@ -183,6 +184,12 @@ module.exports = { name: GROUPING_TIMESTAMP_AND_LAST_REPETITION_TIME_AND_ID_INDEX_NAME, }); + await projectDailyEventsCollection.createIndex({ + groupHash: 1, + }, { + name: DAILY_EVENTS_GROUP_HASH_INDEX_NAME, + }); + await projectEventsCollection.createIndex({ 'payload.release': 1, }, From 52ae696468992c1451ff3b7c95a1201dea9ea208 Mon Sep 17 00:00:00 2001 From: Reversean Date: Tue, 21 Jul 2026 19:27:13 +0300 Subject: [PATCH 2/2] fix(ai): improve AI prompt formatting and add gateway fallback Restructure the CTO instruction prompt with explicit Markdown formatting rules (consistent list indentation, no tabs, no nested code blocks) so the model's output renders correctly. Switch to deepseek/deepseek-v4-flash and add a gateway provider fallback order (novita, azure, deepseek) so requests survive a single provider outage. Drop the now-unneeded hand-written ambient types for the `ai`/`@ai-sdk/openai` modules. Co-authored-by: Gleb Kiva --- package.json | 2 +- src/integrations/vercel-ai/index.ts | 8 ++++-- .../vercel-ai/instructions/cto.ts | 25 +++++++++++++++---- src/types/vercel-ai.d.ts | 18 ------------- 4 files changed, 27 insertions(+), 26 deletions(-) delete mode 100644 src/types/vercel-ai.d.ts diff --git a/package.json b/package.json index 674c52be..1e9ebca4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hawk.api", - "version": "1.5.5", + "version": "1.5.6", "main": "index.ts", "license": "BUSL-1.1", "scripts": { diff --git a/src/integrations/vercel-ai/index.ts b/src/integrations/vercel-ai/index.ts index b063b4c4..c9382eb0 100644 --- a/src/integrations/vercel-ai/index.ts +++ b/src/integrations/vercel-ai/index.ts @@ -1,6 +1,5 @@ import { EventAddons, EventData } from '@hawk.so/types'; import { generateText } from 'ai'; -import { openai } from '@ai-sdk/openai'; import { eventSolvingInput } from './inputs/eventSolving'; import { ctoInstruction } from './instructions/cto'; @@ -17,7 +16,7 @@ class VercelAIApi { /** * @todo make it dynamic, get from project settings */ - this.modelId = 'deepseek/deepseek-v3.1'; + this.modelId = 'deepseek/deepseek-v4-flash'; } /** @@ -32,6 +31,11 @@ class VercelAIApi { model: this.modelId, system: ctoInstruction, prompt: eventSolvingInput(payload), + providerOptions: { + gateway: { + order: ['novita', 'azure', 'deepseek'], + }, + }, }); return text; diff --git a/src/integrations/vercel-ai/instructions/cto.ts b/src/integrations/vercel-ai/instructions/cto.ts index 9d267044..111a1588 100644 --- a/src/integrations/vercel-ai/instructions/cto.ts +++ b/src/integrations/vercel-ai/instructions/cto.ts @@ -1,9 +1,24 @@ export const ctoInstruction = `Ты технический директор ИТ компании, тебе нужно пояснить ошибку и предложить решение. -Предоставь ответ в следующем формате: +Предоставь ответ **строго** в следующем формате на русском языке: -1. Описание проблемы -2. Решение проблемы -3. Описание того, как можно предотвратить подобную ошибку в будущем +[Краткое summary] -Ответь на русском языке.`; +## Описание проблемы +[Подробный, но лаконичный анализ сути проблемы] + +## Решение +[Конкретные шаги по исправлению + рекомендуемый лучший вариант] + +## Как избежать повторения +[Как предотвратить повторение подобной ошибки в будущем: процессы, инструменты, архитектурные решения, code review и т.д.] + +**Formatting instructions:** +- Output only valid Markdown. +- Use consistent indentation for all nested lists. +- Never use tabs instead of spaces. +- Use links if necessary. +- Never use numbering in headings. +- Prefer sections with nested headings to avoid deeply-nested lists. +- Never nest inline code-blocks inside headings. +- Never nest multiline code-blocks inside lists.`; diff --git a/src/types/vercel-ai.d.ts b/src/types/vercel-ai.d.ts deleted file mode 100644 index 33d02c19..00000000 --- a/src/types/vercel-ai.d.ts +++ /dev/null @@ -1,18 +0,0 @@ -declare module 'ai' { - /** - * Minimal type for generateText used in server-side integration. - */ - export function generateText(input: { - model: any; - system?: string; - prompt: string; - }): Promise<{ text: string }>; -} - -declare module '@ai-sdk/openai' { - /** - * Minimal types for OpenAI provider. - */ - export function createOpenAI(config?: { apiKey?: string }): (model: string) => any; - export const openai: (model: string) => any; -}