Skip to content

Azure Functions — Interview Prep Notes (ImageProcessor project)

Code-grounded notes on the actual ImageProcessor function you built, for quick recall at Siemens L2. Full theory reference: Study Notes/Azure/04. Azure Functions — Complete Reference.md.


What the function does

ProcessImage — BlobTrigger, fires on upload to originals/{name}. Reads the stream twice, produces two derivatives:

  • 150x150 crop → thumbnails container
  • 800x800 max-fit → web container

Uses SixLabors.ImageSharp for resize, uploads via a fresh BlobServiceClient with DefaultAzureCredential (Managed Identity / Azure AD, not connection string) pointed at averblobstore.


Terminology to have cold

  • Isolated worker model: your code runs in its own process, not inside the Functions host. FUNCTIONS_WORKER_RUNTIME: dotnet-isolated in local.settings.json confirms this project uses it. Full control over .NET version (net8.0 here), required for .NET 8+. In-process is the deprecated alternative that shares the host process.
  • BlobTrigger binding expression: "originals/{name}" — Azure extracts the blob's filename from the path and injects it as the string name parameter automatically. No manual parsing.
  • Consumption plan (implied by this being a simple learning demo): pay-per-execution, scales to zero, cold starts of 2-5s acceptable here since image processing is async and nobody's waiting on a response.
  • Two storage accounts, two jobs — this project's local.settings.json shows both:
  • AzureWebJobsStorage (account averimagestore) — Functions runtime's own bookkeeping: blob trigger checkpointing, distributed locks so the same blob isn't processed twice, function state.
  • BlobStorageConnection (account averblobstore) — your application data, where originals/thumbnails/web actually live. These are correctly separated in this project — good talking point on why (avoids conflating runtime noise with app data, cleaner access control).

Gap between the code and best practice — be ready to discuss this honestly

This is the most interesting part to walk through in an interview: you can show you know the "right" pattern even though the demo code takes shortcuts.

  1. No three-line-function rule applied. The reference doc's own principle: a Function should be a thin adapter delegating to a portable interface (IImageProcessor), with zero Azure-specific logic inside. This ProcessImage.Run method has all the resize/upload logic inline — not extracted to a service. If asked "would you ship this as-is," the honest answer is no — you'd extract an IImageProcessor.ProcessAsync(stream, name) so the Function itself is 1-2 lines, matching the pattern you already use with IDocumentStore in AverAzure.

  2. Mixed credential strategy. local.settings.json uses connection strings (AccountKey=...) for both AzureWebJobsStorage and BlobStorageConnection, but the code itself constructs BlobServiceClient with DefaultAzureCredential() (Managed Identity) rather than reading the connection string. This is a local-dev-only inconsistency — locally it likely falls back to Azure CLI/VS credential via DefaultAzureCredential's credential chain rather than actually using the BlobStorageConnection value. In deployed Azure, this would need Storage Blob Data Contributor role granted to the Function App's identity on averblobstore. Good to explain: "locally I authenticate via my own Azure CLI login through the default credential chain; in Azure this becomes the Function App's managed identity."

  3. New BlobServiceClient per invocation. Every trigger fire constructs a brand new BlobServiceClient. Fine at low volume, but the reference pattern is to inject it once via DI (builder.Services.AddSingleton<BlobServiceClient>(...) in Program.cs) so connections/credential tokens are reused. Program.cs here only wires up Application Insights — no custom DI registrations at all. Worth mentioning as the obvious next iteration.

  4. Double stream read via stream.Position = 0. Works here because BlobTrigger gives you a seekable Stream, but worth knowing this only works because Consumption plan's blob trigger buffers the blob into a seekable stream — not guaranteed for all trigger/stream types (e.g. HTTP request streams are often forward-only).


Likely interview questions and how to answer from this code

"Walk me through what happens when an image lands in Blob Storage." Blob uploaded to originals/ → Consumption plan's blob trigger (backed by Azure Queue Storage polling under AzureWebJobsStorage) picks up the event, may take up to ~10 min in low-traffic scenarios due to polling → Function host spins up (or reuses a warm instance) → ProcessImage.Run invoked with the blob stream and extracted filename → resize twice → upload to two other containers.

"Why Functions here and not your Worker Service / RabbitMQ pattern from PEPPOL?" Straight from the reference doc's framing — image processing is sporadic, stateless, no strict latency requirement, no complex delivery guarantees. PEPPOL is steady throughput, stateful (correlation IDs, retries, reconciliation), latency-sensitive compliance webhooks. That contrast is the intended interview answer.

"What would break this in production?" - Blob trigger polling delay (up to 10 min on Consumption) — unacceptable if near-real-time processing were required; would need Event Grid–based trigger instead. - No error handling / retry visible in ProcessImage.Run — a failure mid-way (e.g. after thumbnail upload, before web upload) leaves inconsistent state with no compensation. - No idempotency check — if the trigger fires twice for the same blob (queue-based triggers are at-least-once), both derivatives get regenerated and overwritten (harmless here since overwrite: true, but worth naming the guarantee explicitly: idempotent by virtue of deterministic output + overwrite, not by dedup logic).

"How is logging wired up and would you see everything in App Insights?" host.json explicitly sets Function.ProcessImage.User: Information — necessary because isolated worker filters out Information by default; without that line your _logger.LogInformation calls in ProcessImage would silently never appear.


Quick facts to have ready

  • Target framework: net8.0, isolated worker, Functions v4
  • Packages: Microsoft.Azure.Functions.Worker.Extensions.Storage.Blobs, SixLabors.ImageSharp for resizing
  • Storage accounts: averimagestore (runtime), averblobstore (app data)
  • Containers: originals (trigger source), thumbnails (150x150 crop), web (800x800 max)