Створення для великих систем і довготривалих фонових завдань.
Автор: Ilias Chebbi на UnsplashКілька місяців тому я взяв на себе роль, яка вимагала створення інфраструктури для потокового медіа (аудіо). Але крім подачі аудіо як потокових фрагментів, існували довготривалі завдання з обробки медіа та розширений конвеєр RAG, який забезпечував транскрипцію, транскодування, вбудовування та послідовні оновлення медіа. Створення MVP з виробничим мисленням змусило нас повторювати процес, доки ми не досягли безперебійної системи. Наш підхід полягав в інтеграції функцій та основного стеку пріоритетів.
Протягом процесу створення кожна ітерація була відповіддю на негайну і часто "всеохоплюючу" потребу. Початковою проблемою було створення черги завдань, для чого цілком підходив Redis; ми просто запускали і забували. Bull MQ у фреймворку NEST JS надав нам ще кращий контроль над повторними спробами, відставаннями та чергою мертвих листів. Локально та з кількома корисними навантаженнями у виробництві ми налагодили правильний потік медіа. Незабаром ми були обтяжені вагою спостережуваності:
Логи → Запис завдань (запити, відповіді, помилки).
Метрики → Скільки / як часто ці завдання виконуються, не вдаються, завершуються тощо.
Трасування → Шлях, який пройшло завдання через сервіси (функції/методи, викликані в межах шляху потоку).
Ви можете вирішити деякі з цих проблем, розробляючи API та створюючи спеціальну панель управління для їх підключення, але проблема масштабування буде достатньою. І насправді ми розробили API.
Виклик управління складними, довготривалими бекенд-робочими процесами, де збої повинні бути відновлюваними, а стан повинен бути стійким, Inngest став нашим архітектурним порятунком. Він фундаментально переосмислив наш підхід: кожне довготривале фонове завдання стає фоновою функцією, яка запускається конкретною подією.
Наприклад, подія Transcription.request запустить функцію TranscribeAudio. Ця функція може містити покрокові запуски для: fetch_audio_metadata, deepgram_transcribe, parse_save_trasncription та notify_user.
Основним примітивом стійкості є покрокові запуски. Фонова функція внутрішньо розбивається на ці покрокові запуски, кожен з яких містить мінімальний, атомарний блок логіки.
Абстракція функції Inngest:
import { inngest } from 'inngest-client';
export const createMyFunction = (dependencies) => {
return inngest.createFunction(
{
id: 'my-function',
name: 'My Example Function',
retries: 3, // retry the entire run on failure
concurrency: { limit: 5 },
onFailure: async ({ event, error, step }) => {
// handle errors here
await step.run('handle-error', async () => {
console.error('Error processing event:', error);
});
},
},
{ event: 'my/event.triggered' },
async ({ event, step }) => {
const { payload } = event.data;
// Step 1: Define first step
const step1Result = await step.run('step-1', async () => {
// logic for step 1
return `Processed ${payload}`;
});
// Step 2: Define second step
const step2Result = await step.run('step-2', async () => {
// logic for step 2
return step1Result + ' -> step 2';
});
// Step N: Continue as needed
await step.run('final-step', async () => {
// finalization logic
console.log('Finished processing:', step2Result);
});
return { success: true };
},
);
};
Модель, керована подіями, Inngest надає детальне розуміння кожного виконання робочого процесу:
Застереження щодо покладання на чисту обробку подій полягає в тому, що хоча Inngest ефективно ставить у чергу виконання функцій, самі події не ставляться у внутрішню чергу у традиційному сенсі брокера повідомлень. Ця відсутність явної черги подій може бути проблематичною у сценаріях з високим трафіком через потенційні умови гонки або втрачені події, якщо кінцева точка прийому перевантажена.
Щоб вирішити це та забезпечити сувору стійкість подій, ми впровадили спеціальну систему черг як буфер.
AWS Simple Queue System (SQS) була системою вибору (хоча будь-яка надійна система черг є можливою), враховуючи нашу існуючу інфраструктуру на AWS. Ми спроектували систему з двох черг: Основна черга та Черга мертвих листів (DLQ).
Ми створили середовище робітника Elastic Beanstalk (EB), спеціально налаштоване для споживання повідомлень безпосередньо з Основної черги. Якщо повідомлення в Основній черзі не вдається обробити робітником EB певну кількість разів, Основна черга автоматично переміщує невдале повідомлення до спеціальної DLQ. Це гарантує, що жодна подія не буде втрачена назавжди, якщо вона не зможе запуститися або бути підхопленою Inngest. Це середовище робітника відрізняється від стандартного середовища веб-сервера EB, оскільки його єдиною відповідальністю є споживання та обробка повідомлень (у цьому випадку, пересилання спожитого повідомлення до кінцевої точки API Inngest).
Недооцінена і досить актуальна частина створення інфраструктури корпоративного масштабу полягає в тому, що вона споживає ресурси, і вони є довготривалими. Архітектура мікросервісів забезпечує масштабованість для кожного сервісу. Сховище, оперативна пам'ять та час очікування ресурсів будуть мати значення. Наша специфікація для типу екземпляра AWS, наприклад, швидко перейшла від t3.micro до t3.small, і зараз зафіксована на t3.medium. Для довготривалих, інтенсивних за CPU фонових завдань горизонтальне масштабування з крихітними екземплярами не вдається, оскільки вузьким місцем є час, необхідний для обробки одного завдання, а не обсяг нових завдань, що надходять до черги.
Завдання або функції, такі як транскодування, вбудовування, зазвичай обмежені CPU та обмежені пам'яттю. Обмежені CPU, оскільки вони вимагають стійкого, інтенсивного використання CPU, та обмежені пам'яттю, оскільки вони часто вимагають значної оперативної пам'яті для завантаження великих моделей або ефективної обробки великих файлів чи корисних навантажень.
Зрештою, ця розширена архітектура, розміщення стійкості SQS та контрольованого виконання середовища робітника EB безпосередньо вище за течією від API Inngest, забезпечила необхідну стійкість. Ми досягли суворого володіння подіями, усунули умови гонки під час сплесків трафіку та отримали енергонезалежний механізм мертвих листів. Ми використовували Inngest для його можливостей оркестрації робочих процесів та налагодження, покладаючись на примітиви AWS для максимальної пропускної здатності повідомлень та стійкості. Отримана система не лише масштабована, але й високо перевірювана, успішно перетворюючи складні, довготривалі бекенд-завдання на безпечні, спостережувані та стійкі до відмов мікрокроки.
Building Spotify for Sermons. було вперше опубліковано в Coinmonks на Medium, де люди продовжують розмову, виділяючи та відповідаючи на цю історію.


