{"slug": "how-i-am-building-an-ai-meeting-assistant-in-asp-net-core-and-avoided-timeout", "title": "How I Am Building an AI Meeting Assistant in ASP.NET Core (And Avoided Timeout Nightmares)", "summary": "A university student building an AI Meeting Assistant as a final-year project implemented ASP.NET Core Background Services to avoid 504 Gateway Timeout errors when processing 20-minute audio recordings. The system downloads audio from Backblaze B2, sends it to a self-hosted transcription service, and passes the text to Google Gemini for structured meeting minutes—a process taking over 90 seconds that previously caused browser timeouts when run in standard API controllers.", "body_md": "For my 4rd-year Software Engineering final project at university, I’m building an AI Meeting Assistant.\n\nThe core feature is simple: A user uploads a 20-minute audio recording of a meeting. My backend downloads it from Backblaze B2, sends it to an selfhosted transcription service to transcribe the speech, and then passes that text to Google Gemini to generate structured meeting minutes that are sent to you email.\n\nThere was just one massive problem: It takes over a minute to process.\n\nIf I ran this logic inside my standard API Controller, the user’s browser would just show a loading spinner for 90 seconds, eventually hitting a 504 Gateway Timeout.\n\nThe solution? ASP.NET Core Background Services. Here is how I implemented a background worker to handle the heavy AI lifting, and the 3 massive \"Gotchas\" I ran into along the way.\n\nTo understand why Background Services are necessary, think of a fast-food restaurant:\n\nThe Controller (The Cashier): The cashier takes your order, hands the ticket to the kitchen, and gives you a receipt. They don't cook the food. If the cashier goes to the back to grill your burger, the line of customers out the door gets angry.\n\nThe BackgroundService (The Kitchen Staff): The kitchen staff doesn't interact with customers. They sit in the back, continuously checking the ticket machine. When a new ticket pops up, they cook the food.\n\nIn ASP.NET Core, Controllers are short-lived (created and destroyed for every HTTP request). But a BackgroundService is long-lived. It is created once when the app starts, and runs continuously until the app shuts down.\n\n*Building the Transcription Worker*\n\nIn .NET, creating a background worker is incredibly easy. You just create a class that inherits from BackgroundService and override the ExecuteAsync method.\n\nHere is the exact skeleton of the TranscriptionWorker I built for my project:\n\n```\npublic class TranscriptionWorker : BackgroundService\n{\n    private readonly IServiceProvider _serviceProvider;\n    private readonly ILogger<TranscriptionWorker> _logger;\n\n    public TranscriptionWorker(IServiceProvider serviceProvider, ILogger<TranscriptionWorker> logger)\n    {\n        _serviceProvider = serviceProvider;\n        _logger = logger;\n    }\n\n    protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n    {\n        _logger.LogInformation(\"Transcription Background Worker started.\");\n\n        while (!stoppingToken.IsCancellationRequested)\n        {\n            try\n            {\n                // 1. Check the database for newly uploaded audio files\n                using var scope = _serviceProvider.CreateScope();\n                var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();\n\n                var pendingAudio = await context.AudioFiles\n                    .FirstOrDefaultAsync(a => a.Status == Status.Pending, stoppingToken);\n\n                if (pendingAudio != null)\n                {\n                    // 2. Hand it off to the processing service (Groq -> Gemini)\n                    var processor = scope.ServiceProvider.GetRequiredService<IAudioProcessingService>();\n                    await processor.ProcessAudioAsync(pendingAudio.Id);\n                }\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, \"Error in TranscriptionWorker loop.\");\n            }\n\n            // 3. Go to sleep for 30 seconds before checking again\n            await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);\n        }\n    }\n}\n```\n\nTo turn it on, I just registered it in my Program.cs:\n\n```\nbuilder.Services.AddHostedService<TranscriptionWorker>();\n```\n\nNow, when a user uploads an audio file, my API instantly saves it to the database with a Pending status and replies to the user: \"Upload successful! We'll notify you when the minutes are ready.\" Meanwhile, the worker silently picks it up in the background.\n\nIf you are building a .NET app that integrates with AI APIs, file processing, or heavy database tasks, stop doing it in the HTTP request pipeline. Give BackgroundService a try!\n\nHave you used Background Services in your projects? What kind of tasks are you running in the background? Let me know in the comments below!", "url": "https://wpnews.pro/news/how-i-am-building-an-ai-meeting-assistant-in-asp-net-core-and-avoided-timeout", "canonical_source": "https://dev.to/victor_mwangi_d224324203c/how-i-am-building-an-ai-meeting-assistant-in-aspnet-core-and-avoided-timeout-nightmares-3mmd", "published_at": "2026-06-03 23:12:50+00:00", "updated_at": "2026-06-03 23:41:57.683180+00:00", "lang": "en", "topics": ["ai-products", "ai-tools", "ai-infrastructure", "natural-language-processing", "generative-ai"], "entities": ["ASP.NET Core", "Backblaze B2", "Google Gemini", "AI Meeting Assistant"], "alternates": {"html": "https://wpnews.pro/news/how-i-am-building-an-ai-meeting-assistant-in-asp-net-core-and-avoided-timeout", "markdown": "https://wpnews.pro/news/how-i-am-building-an-ai-meeting-assistant-in-asp-net-core-and-avoided-timeout.md", "text": "https://wpnews.pro/news/how-i-am-building-an-ai-meeting-assistant-in-asp-net-core-and-avoided-timeout.txt", "jsonld": "https://wpnews.pro/news/how-i-am-building-an-ai-meeting-assistant-in-asp-net-core-and-avoided-timeout.jsonld"}}