Skip to content
CAMPUX Cloud Bootcamp Phase Four · Class Forty-One
Phase Four — Operate, Secure & AI
Reading 41 min · Drills 6 · 1 Lab
Developer skills · AZ-204 retired 2026
Class Forty-One

Azure Functions

The worker Class Forty kept promising: code that wakes when a message arrives, runs for eight seconds, bills for eight seconds, and does not exist the rest of the day — the consumer at the end of the queue, and the cheapest compute Azure sells for work that happens in bursts.

● Screen walkthrough Not yet recorded · ~8 min
Reel · 00:00 / 08:00

Create a Function App, add a timer-triggered function, deploy it, and watch it fire on schedule and scale to zero between runs.

Placeholder — the class below stands alone until the reel lands
§1

Code that isn't running most of the time

Class Forty ended with a promise: a worker would drain the order-events queue. The obvious way to build that worker is a program that runs forever — a virtual machine or an App Service that sits in a loop, polling the queue, waiting for something to do. It works, and it is also the January-trough problem from Class One in a new costume: the worker bills for twenty-four hours a day to do the few minutes of real work that actually arrive, and ninety-nine percent of what you pay for is a process staying awake in case a message shows up. You already know Azure's answer to "billed for existing, not for working," because Class Twenty-Seven's Container Apps job scaled to zero. Azure Functions is that idea taken to its smallest unit: a single piece of code that does not run — does not exist as a live process — until an event wakes it, runs for as long as the work takes, and then disappears.

The shift is in what you are responsible for. With a VM you own the machine, the operating system, the runtime, the scaling, and the polling loop, and you rent the code some space inside all of that. With a Function you own the code and nothing else: you write a handler that says "when an order message arrives, do this," and Azure owns the host it runs on, the act of watching the queue, the decision to start one copy or fifty when a backlog lands, and the decision to stop them all when it clears. This is what "serverless" actually names — not the absence of servers, but the absence of servers you manage. The servers are Microsoft's problem; the function is yours.

Two workloads from earlier in the bootcamp are Functions waiting to be recognised. The nightly price import from Class Eleven — run at 02:00, work for a few minutes, cost nothing the other twenty-three hours and fifty-odd minutes — is a function on a timer. The order-events consumer from Class Forty — wake on each message, fulfil the order, go back to sleep — is a function on a queue trigger. Neither wants a server standing by; both want code that appears when there is a reason and vanishes when there is not.

You bring the function; Azure brings everything around it.

§2

Triggers and bindings — the whole programming model

A Function is three things, and once you can name them the product stops being mysterious: a trigger, the code, and its bindings. The trigger is the one event that wakes the function, and there is exactly one per function. The bindings are the declarative connections to the data the function reads and writes — zero or more of them — so the plumbing to Azure services becomes configuration instead of SDK boilerplate you hand-write and maintain.

Trigger & binding
A trigger is the single event that starts a function — a queue or Service Bus message, an HTTP request, a timer/cron schedule, a new blob, an Event Grid event. A binding is a declarative input or output connection — read this blob, write to that queue — that hands the function its data without connection code.

The triggers are the map of what Functions is for. A queue or Service Bus trigger makes a function the consumer at the end of Class Forty's queue — the platform does the peek-lock, hands your code the message, and completes or dead-letters it based on whether you threw. A timer trigger is cron in the cloud, which is the price import. An HTTP trigger makes a function a tiny API endpoint — a webhook receiver, a lightweight backend — often sat behind the Class Thirty-Eight gateway. A blob or Event Grid trigger reacts to something happening in the estate: an image uploaded, a resource created. The shape is always the same — something happens, a function wakes, it runs. Bindings then spare you the glue: an output binding that writes the result to a "fulfilled" queue is one line of configuration, not a page of client setup, and the senior habit is to let the binding carry the plumbing and keep your code about the work.

Input, output, and the direction of a binding

The word that trips people is direction. A binding is either in or out, and the two do opposite work. An input binding reads something and hands it to your code before the function body runs — the customer record fetched by the order id on the message, sitting in a parameter you never wrote a query for. An output binding takes what your code returns or sets and writes it after the body finishes — the result dropped onto a "fulfilled" queue by assigning one variable, no client, no connection string in your code, no retry loop you maintain. The trigger is a special input that also wakes the function; every other connection is a plain binding whose only job is to move data in or out. Say it as a sentence in the interview: one trigger, then inputs read for you and outputs written for you, all declared in configuration rather than coded by hand.

HTTP
Wakes on a request; the function is a small API or webhook receiver, usually sat behind the Class Thirty-Eight gateway. The one trigger whose caller is waiting on the line, so cold starts are felt here and nowhere else.
Timer
Wakes on a six-field CRON schedule — cron in the cloud, with no server kept alive to hold it. The Class Eleven price import, priced at zero the rest of the day.
Queue / Service Bus
Wakes once per message and is the consumer at the end of Class Forty. At-least-once delivery, so the handler must be idempotent; a Storage queue trigger retries five times then parks the message on an automatic poison queue, while Service Bus adds sessions, ordering, and a dead-letter queue you can inspect and retry by hand.
Blob
Wakes when an object lands in a container — resize the image, parse the upload. The classic source polled with a lag; the Event Grid-backed blob source fires promptly instead of on a scan.
Event Grid
Wakes on an event from across the estate — a resource created, a blob written, a custom event you publish. The push-based spine for reacting to things that happen, rather than messages that queue.
§3

The hosting plan is the decision that bites

The code is the easy part; the plan you run it on is the choice that shows up in the bill and the incident channel, and it is the §3 skill. Three answers matter.

Table 1 — the Functions hosting plans, decided on the trade you can accept
QuestionConsumption (classic)Flex ConsumptionPremiumApp Service plan
Scales to zero?Yes — pay only per runYes — pay only per runNo — keeps warm instancesNo — always on
Cold starts?Yes — first call after idle is slowYes, but fast — and paid always-ready instances remove themNo — pre-warmedNo
VNet / private endpoints?NoYesYesYes
Max run per execution5 min default, 10 max30 min default, extendableLong / unboundedUnbounded
Best forExisting apps; the legacy incumbentNew serverless work — the recommended defaultLatency-critical, heavy, VNet-boundYou already run an App Service plan

Read the table as one question — what can you tolerate? The serverless idea comes in two generations. Classic Consumption is the incumbent: it scales from zero to many and bills per execution and gigabyte-second, and its two prices are a cold start — the first request after the function has gone idle waits while Azure spins a host, which a background queue drain never notices and a user-facing HTTP endpoint very much does — and a five-to-ten-minute execution ceiling that quietly rules out long jobs. Flex Consumption is where Microsoft now points new work: it keeps the whole serverless bargain — scale to zero, pay per run — while starting faster from cold, running to thirty minutes by default, and reaching into VNets; if a cold start is genuinely unaffordable, always-ready instances remove it for a fee. Premium stops pretending to be serverless: warm instances all the time, no cold start ever, at a standing floor cost. The App Service plan is the answer when you already run one and have spare capacity — the functions ride along, always on, no cold start, no scale-to-zero saving. The decision rule is the Container-Apps rule again: start on Flex Consumption, and move only when a named requirement — zero cold start at any price, an unbounded run, an existing plan with room — forces you.1

What actually decides to scale — the controller you never see

On the serverless plans you do not set an instance count, so something has to. That something is the scale controller, a component that watches each trigger's backlog and decides, second by second, how many copies of your function to run. It reads the depth of the queue, the age of the oldest Service Bus message, the rate of HTTP requests, and adds or removes instances to keep up — scaling out to dozens or hundreds under a Black Friday backlog and back to zero when the work clears. You wrote no autoscale rule and named no CPU threshold; the trigger's own backlog is the signal. This is what event-driven scaling means: the number of running functions tracks the number of pending events, not a metric on the box.

Two consequences follow, and both are interview-shaped. First, scale-out is bounded — a per-app maximum instance count exists, and on Consumption a burst is rate-limited so a thousand instances do not appear in a single second — which matters the moment your function fans out onto a database that cannot take a thousand connections. The senior move is to cap the concurrency on purpose (the host's batch and concurrency settings, or the plan's maximum) rather than let the controller stampede a fixed backend, which is the failure the Think-in-Systems box below names. Second, the newer plans and triggers use target-based scaling: instead of adding one instance at a time, the controller reads the backlog and the per-instance throughput and jumps straight to roughly the right instance count, draining a spike in far fewer steps. You do not configure the controller so much as shape what it reacts to — and knowing it is there is the difference between "Functions just scales" and being able to say how, and where that scaling stops.

Play

Play it through

Three minutes, two workloads. Put Consumption on the job nobody is watching, then put Premium on the one a partner is waiting on. It plays on its own and stops when it needs your hands.

§4

The three rules that keep a function honest

Functions are unforgiving of a few assumptions carried over from long-running code, and every one of the mistakes is an interview question. First, a function is stateless: it keeps nothing in memory between runs, because the instance that handled the last message may not be the one that handles the next, or may not exist at all. Anything that must persist — a running total, a cursor, a half-finished workflow — lives in storage, a queue, or a database, never in a variable. A function that "remembers" is a function that works in testing and fails the moment it scales past one instance.

Second, a function must be idempotent, for the exact reason Class Forty drilled: queue and Service Bus triggers deliver at-least-once, so your function will occasionally run twice on the same message — a redelivery after a host recycle, a lock that lapsed mid-run. Keying on the order id and checking before acting is not optional hygiene here; it is the difference between a redelivery being invisible and a customer being charged twice. The trigger's at-least-once contract and the function's idempotency are two halves of one design.

Third, keep a function short and single-purpose. The ten-minute limit is a hint about intent, not just a cap: a function should do one unit of work and end. Chaining a long synchronous sequence inside one function — charge, then wait for the warehouse, then wait for the courier, then email — fights both the time limit and the stateless model, and when it fails halfway you cannot tell what already happened. Work that spans steps, waits, or fan-out wants orchestration, which is §5.2

One function, one job, no memory.

§5

Durable Functions — the phrase for workflows

The moment a job stops being "handle this one message" and becomes "run these five steps, some of which wait," a plain function's statelessness and ten-minute limit turn from features into walls. The answer is Durable Functions, an extension that adds a stateful orchestrator: a function that describes a workflow in ordinary code — call this, await the result, call that, wait for a human to approve, fan out to a hundred parallel tasks and fan back in — while the runtime checkpoints its progress to storage after every step and replays it to survive restarts, timeouts, and the stateless model underneath.

Durable Functions
An extension to Azure Functions for stateful workflows: an orchestrator function coordinates multiple activity functions — chaining, fan-out/fan-in, waiting for external events or human approval, long-running timers — with the runtime persisting and replaying state so a multi-step process survives restarts and outlives any single execution.

You do not need it for the order-events consumer, which is one message and one job. You reach for it when fulfilment becomes a real workflow — charge the card, and only if that succeeds reserve the stock, then wait for the warehouse to confirm, then email the customer — because that sequence has ordering, failure branches, and a wait no single stateless run should hold open. Naming Durable Functions when the interviewer describes a multi-step process is the signal that you know where a plain function stops; the pattern also outlives Azure, because "orchestrator plus activities plus checkpointed state" is how every serverless workflow engine, from Step Functions to Temporal, is shaped.3

The four patterns worth naming out loud

Durable Functions is not one trick; it is a small set of shapes an interviewer will describe without naming, waiting for you to name them. Four are worth having ready, and each is a workflow a single stateless function could not hold.

Function chaining
Run steps in a fixed order, each starting only if the last succeeded: charge → reserve → confirm → email. The orchestrator awaits each activity in turn and checkpoints between them, so a mid-run restart resumes at the step it reached rather than re-charging the card.
Fan-out / fan-in
Start many activities in parallel, then wait for all of them and aggregate: transcode one video into a dozen resolutions at once, then write a single "done" record when the last returns. Tracking which of the parallel tasks have finished is the runtime's job, not a table you maintain.
Async HTTP / monitor
Kick off long work, hand the caller a status URL to poll, and let a durable timer watch an external job — checking a report every five minutes for up to an hour without holding a request or an instance open the whole time.
Human interaction
Pause and wait for an external event — a manager's approval, a customer's reply — with a timeout that takes a default action if no one answers in seventy-two hours. The orchestration sleeps, costing nothing, and wakes when the event arrives or the timer fires first.

Underneath these sits a third function type beyond orchestrators and activities: the entity function, a small piece of addressable, durable state — a counter, a cart, a per-customer tally — that many callers can update in order without a race. It is the honest home for the "running count" that Drill 04 forbids in a module variable: state that must persist and be shared, made explicit and durable rather than smuggled into memory the next instance will not have.

Functions, Container Apps, or Logic Apps

Three Azure services answer "run my code when something happens," and the interview question is which, and why. They are less rivals than three points on one line — how much you write versus how much the platform already did.

Table 2 — three ways to run event-driven work, from most code to least
ServiceYou writeReach for it when
Azure FunctionsA short handler per event, in codeThe unit of work is small, event-driven and bursty — the default for glue and queue consumers
Container AppsA whole container image — your runtime, your dependenciesThe work needs a full container, a long-running service, or a runtime Functions does not host (Class Twenty-Seven)
Logic AppsAlmost no code — a visual workflow of prebuilt connectorsThe job is wiring SaaS systems together — "a form is submitted, add a row and send mail" — more integration than computation

The rule the answer should carry: Logic Apps when the value is the connectors and you would rather not write code; Functions when it is a small piece of your own logic per event; Container Apps when the thing that runs is larger than a function or has to be a container. Durable Functions and Logic Apps overlap on orchestration — both run multi-step workflows — and the honest split is code versus canvas: Durable Functions for a developer who wants the workflow in source control and under test, Logic Apps for a workflow that is mostly connecting other people's systems. Naming all three, and the axis between them, is a stronger answer than defending Functions as the tool for every job.

Case File · Campux Retail

The worker Class Forty promised, finally built

a Function App drains the queue, scales to zero, and grows an orchestrator

The consumer at the end of Campux's orders topic is a Function App on the Consumption plan, and it is almost boringly small: one function, a Service Bus trigger on the fulfilment subscription, and a handler that is idempotent on the order id from its first line — the discipline Class Forty demanded, now load-bearing. Each message wakes the function; it charges, reserves, and emails; it completes the message, or throws and lets Service Bus dead-letter the poison after three tries. When the Black Friday backlog lands, Azure scales the function from zero to dozens of instances to drain it, then back to zero when the queue empties — and the bill for the quiet overnight hours, when nothing runs, is nothing. The nightly price import moves here too, as a second function on a 02:00 timer trigger, and the last always-on VM in the estate is switched off.

Then fulfilment grows the way real fulfilment does. Finance wants the charge to happen before the stock reservation, the warehouse confirmation to be waited on, and the customer email sent only after all of it succeeds — with a clean record, at any moment, of exactly which step an order reached. That is no longer one function's job; a single stateless run cannot hold a warehouse wait open, and the ten-minute limit forbids it trying. So fulfilment becomes a Durable Functions orchestration: an orchestrator chains charge → reserve → await-warehouse → email as activity functions, checkpointing after each, surviving a host recycle mid-wait without losing its place. Six functions, no servers, a workflow you can point at and read — and outside the two annual peaks, the compute bill for the whole of order fulfilment rounds to zero. The checkout from Class Forty still does its one thing in a blink; the work behind it now wakes only when there is work, which is the whole argument of the bootcamp, kept.

Fig. 1 · Campux's Function App — woken by events, billed only when it runs
Service Bus orders → fulfilment timer · 02:00 price import HTTP request webhook / API triggers Function App Consumption plan idempotent handler scales 0 → many → 0 storage / state database binding output bindings scales to zero — bills only when it runs
One function per job, each woken by a trigger — a Service Bus message, a timer, an HTTP call — with bindings carrying the data in and out so the code is about the work, not the plumbing. On Consumption it scales from zero to many and back, billing only for the runs, and because the trigger is at-least-once the handler must be idempotent. Multi-step fulfilment moves to a Durable Functions orchestration.
Watch · Microsoft Learn

The official pages, and a CAMPUX overview

Read the Functions overview and the hosting-plan comparison before the lab
Microsoft Learn · Docs

Azure Functions — overview (triggers, bindings, the model)
learn.microsoft.com/azure/azure-functions/functions-overview

Azure Functions hosting options — Consumption, Flex, Premium, Dedicated
learn.microsoft.com/azure/azure-functions/functions-scale

CAMPUX overview video

A Function App created on Consumption, a timer-triggered function firing once a minute, the invocation list as the bill, and a queue trigger draining order-events — will live here. Video to be added.

Lab · A function that wakes on a schedule

A Function App, a timer trigger, and a run that costs nothing between runs

~15 minutes · portal + Cloud Shell · Consumption plan, effectively free

You matched a plan to a workload above. Below, build the timer-triggered function for real and watch it scale to zero between runs. Create the smallest real Function App, give it a timer-triggered function, and watch it fire on schedule and bill for the seconds it runs.

  1. A Function App needs a storage account for its own bookkeeping; create both on the Consumption plan:

    az group create --name rg-func-lab --location eastus
    az storage account create -n stfnlab<initials> -g rg-func-lab --sku Standard_LRS
    az functionapp create -n fn-campux-<initials> -g rg-func-lab \
      --consumption-plan-location eastus \
      --runtime node --functions-version 4 \
      --storage-account stfnlab<initials>
    What to notice: --consumption-plan-location is the whole §3 decision made in one flag — scale to zero, pay per run, accept cold starts. The storage account is not optional: Functions keeps its trigger state and logs there, which is also where Durable Functions checkpoints workflows.
  2. In the portal: open the Function App → Create functionTimer trigger. Set the schedule to every minute with the CRON expression 0 */1 * * * * and create it.

    What to notice: the timer trigger is cron in the cloud — the Class Eleven price import with no server to keep it running. One function, one trigger, one job. The six-field CRON includes seconds, which trips people who bring five-field habits from Linux.
  3. Open the function → Monitor (or Logs) and watch it fire once a minute, each run a few milliseconds of billed time. Between runs, nothing is running and nothing is billed.

    What to notice: the invocation list is the bill — each row is a run you paid for, and the gaps between them cost nothing. This is the trough from Class One finally priced correctly: the function exists only when there is a reason for it to.
  4. Tear it down so the timer stops and nothing lingers:

    az group delete --name rg-func-lab --yes --no-wait
    The lesson: you deployed compute that costs money only while it works. Swap the timer for a queue trigger and you have Class Forty's consumer; swap it for an HTTP trigger and you have a tiny API — same model, different first line.
Note · the exact create flags and the portal's function-authoring flow shift between Functions runtime versions and languages; the trigger-plus-bindings model is the stable part. Consumption is effectively free at this volume, but delete the group so the storage account and any logs stop accruing.
Think in systems

Zoom out: cheap-per-run is not free, and scale-to-zero has a first customer

A function that costs nothing at rest feels like it removed a constraint. It moved one. Reason about what event-driven, scale-to-zero compute does to the system around it before the exam.

Feedback loops

A queue backs up, so Functions scales out to dozens of instances to drain it — and all of them hit the same database at once, which slows, which makes each function run longer, which makes Functions scale out further. Elastic compute in front of a fixed backend is a stampede waiting for a trigger. What limits the concurrency, and where does the backpressure live?

Dependencies & coupling

Scale-to-zero means the first request after idle pays the cold start. A background drain never notices; a customer-facing HTTP function does, and now your latency depends on how recently someone else called it. You traded a standing cost for a variable one — who feels the variance, and is it the person you least want to?

The constraint

Functions scales the compute effortlessly, so the ceiling moves to whatever it calls — the database connections, the downstream API's rate limit, the Service Bus throughput. The wall is no longer your worker; it is the least elastic thing behind it. Adding function instances past that point just queues the contention somewhere less visible.

Second-order effects

Per-execution billing makes cost scale with traffic, which is wonderful until a retry storm or a recursive trigger — a function that writes to the queue that triggers it — turns a bug into a runaway invoice. Cheap-per-run removed the standing cost and added a new failure mode: the loop that bills. What caps it?

What breaks when it scales

The ten-minute limit and statelessness are invisible at one message a minute and fatal at ten thousand a second with a step that waits. What breaks first as volume climbs — the execution limit, the downstream, or the assumption that one function could hold the whole workflow? Which is a plan change and which is Durable Functions?

The engineer who ships is asked "does it run?" The engineer who gets promoted is asked "and what does it stampede when it does?" — and has already capped the concurrency.

On the job

Turning a standing cost into a per-run one

You · Cloud Engineer · a VM runs a job for eight minutes and bills for a day

A virtual machine exists to run one nightly job and one queue drain, and it bills twenty-four hours a day to do it. You rewrite the two workloads as Functions — a timer trigger and a queue trigger — switch the VM off, and the compute bill for that work collapses to the seconds it actually runs. Same jobs, same output, a line item that finally matches the work — and you are the one who stopped paying for idle.

Class Forty-One

Examination

Four drills, then two situations. The situations have no marking scheme — write your answer before you reveal the reasoning, or the exercise is worthless. Nothing is stored; this is between you and the page.

Drill 01Recall · pick the plan
A customer-facing HTTP function must answer in under 200 ms almost every call, reach a database over a private endpoint, and sometimes has to trigger twelve minutes of work behind the scenes. Which hosting plan fits the fast path, and what happens to the twelve minutes?
Marked

B — the fast path names two things Consumption cannot give, and the twelve minutes is not a hosting-plan problem at all. "Under 200 ms almost every call" collides with cold starts, which make the first call after idle slow and unpredictable — exactly the person you least want to hit them. "Private endpoint" needs VNet integration, which Consumption limits. Premium or Flex removes both. But every HTTP-triggered function, on every plan, has to answer within roughly 230 seconds regardless — that ceiling belongs to the load balancer sitting in front of it, not to Functions, and no plan and no timeout setting moves it. C is the trap that fails twice: it tries to fix a plan problem with a timeout knob, and the twelve-minute call was never going to survive on any plan's HTTP response. The honest fix is the §5 async pattern — answer immediately, then let a queue pick up the twelve minutes or hand the caller a status URL to poll, instead of holding the line open. A ignores the stated cold-start and VNet requirements to reach for cheapest. D is false on both counts the question was built to test.

Drill 02Recall · triggers & bindings
A function should run when a message lands on the orders Service Bus subscription, read a customer record from a database, and write a result to a "fulfilled" queue. How many triggers and bindings is that?
Marked

B — a function has exactly one trigger, and everything else it touches is a binding. The one event that wakes the function is the Service Bus message; the database read is an input binding and the queue write is an output binding — declarative connections that hand the function its data without connection code. A is the classic confusion: only the thing that starts the function is a trigger, and there is always precisely one. D repeats the error more subtly — a database read does not start the function, so it cannot be a trigger. C is true only if you refuse the model: you can hand-code with SDKs, but bindings exist so you do not, and choosing boilerplate over a binding is choosing to maintain plumbing the platform offered to carry. "One trigger, zero-or-more bindings" is the sentence to have ready.

Drill 03Select three
Which three are true of an Azure Function and must shape how you write one?
Marked

Stateless, idempotent, and time-capped — the three constraints a function is written around. Each changes your code: state goes to storage not variables, the handler checks a natural key before acting, and the work is kept short enough to finish. The two rejects are the mistakes those constraints exist to prevent. "A single function holds a multi-hour workflow open" is exactly what Durable Functions exists because you cannot do — a plain function is stateless and time-capped, so a long wait belongs in an orchestrator, not one run. And "keeps an instance warm at all times" describes Premium, not the Consumption default the question implies; asserting no-cold-starts as a universal truth of Functions is the misconception §3 corrects. The three trues are the design brief; the two falses are the §4 and §5 walls.

Drill 04Spot the error
This design for the fulfilment function is about to ship. One line guarantees an incident under load. Which?
# design: fulfilment function (Consumption)
1.  Service Bus trigger on the fulfilment subscription;
    handler is idempotent on the order id.
2.  Keeps a running count of orders processed in a
    module-level variable, logged each run.
3.  On failure it throws, so Service Bus retries and
    eventually dead-letters per Class 40.
4.  Long multi-step fulfilment is moved to a Durable
    Functions orchestration.
Marked

Line two — the one line that quietly assumes a server. A module-level variable holding a running count works perfectly in testing, where one instance handles every message in sequence, and fails silently in production, where Functions scales to many instances that share no memory and any of which may be recycled between runs. The "count" becomes per-instance, resets without warning, and means nothing — a metric that lies. Persistent state belongs in storage, a database, or a metrics backend (Class Thirty's App Insights), never in a variable that outlives a single execution only by accident. The distractors are the design working: idempotency on a Service Bus trigger is not just possible but required (A inverts §4); throwing to drive retry-then-dead-letter is precisely the Class Forty contract (C); and moving multi-step work to Durable Functions is §5's correct call, not overkill (D). The reviewer's reflex: in serverless code, any state that is not written down is a bug that waits for the second instance.

Situation 01Write before you reveal
A teammate's Consumption function processes an uploaded video and keeps timing out at ten minutes on large files. Their fix: "Move it to an App Service plan so there's no execution limit and it can run as long as it needs." Is that the right call?
Their fix removes the symptom. Ask what the ten-minute limit was trying to tell them about the shape of the work.
Reasoning

Concede that the fix works, then question what it teaches you to stop noticing. Moving to an App Service plan (or Premium) genuinely removes the ten-minute cap, and for some workloads that is the right answer — so do not reject it reflexively. But the timeout was not an arbitrary obstacle; it was the platform telling you the work does not fit the "wake, do one short thing, end" shape a single function is built for. Lifting the limit lets a long, stateful, all-or-nothing job run inside one execution — and the day it fails at minute nine, you have no idea what already happened, no checkpoint, and no way to resume. You removed the alarm, not the fire.

Name the shapes and match the tool to each. If the video processing is genuinely one long computation that cannot be broken up, then long-running compute is the honest need — but a function is a poor host for it, and a container job (Class Twenty-Seven) or a Durable Functions activity with the right plan is a better one. If, more likely, it is several steps — download, transcode, thumbnail, store — then it wants a Durable Functions orchestration: each step its own short activity, checkpointed, resumable, fanning out across sizes if needed. Either way the question to ask first is not "how do I make one function run longer" but "why is this one function doing so much."

Close on the cost the quick fix hides. An App Service plan does not scale to zero, so the moment they move there to dodge the timeout, they also give up the per-run billing that made Functions worth choosing — the video job now bills for a standing plan whether or not a video is being processed. That may be fine; it should be a decision, not a side effect. The sentence to leave them with: the limit isn't the problem — it's the diagnosis; fix the shape of the work, and pick the plan on purpose.

Situation 02Write before you reveal
Finance flags a bill: a Consumption Function App cost more last month than the VM it replaced. The team's instinct is to move it back to a VM. What do you investigate first, and what is the likely story?
Per-run billing means cost scales with runs. A bill that jumped usually means the run count did — find out why before you architect.
Reasoning

Resist the reflex to re-architect before you have read the invoice. "Move it back to a VM" is a large, slow change proposed before anyone has looked at why the number moved — the exact instinct Class Thirty-Two trains you to distrust. Consumption bills per execution and per gigabyte-second, so a bill that jumped almost always means executions or duration jumped. The first move is the metrics, not the migration: how many invocations, of which function, and did the count or the per-run duration change?

Name the usual suspects, because they are specific and fixable. The classic is a runaway or recursive trigger — a function whose output lands on the queue that triggers it, or a retry storm on a persistently failing message multiplying invocations — turning a bug into a per-run invoice. Next is a chatty trigger firing far more than intended (a timer set to every second, a blob trigger on a hot container). Then a genuine, healthy traffic increase, in which case the bill rose because the business did, and the VM would simply have hit a wall instead of a line item. Each has a targeted fix — cap concurrency, fix the loop, dead-letter the poison, right-size the schedule — none of which is "buy a server."

Only then compare honestly, at the real workload. If, after fixing the anomaly, sustained high-volume traffic genuinely makes Consumption more expensive than a right-sized always-on plan, that is a legitimate finding — Consumption wins on spiky and bursty, and a steady firehose can favour a plan with a fixed floor. But that is a priced comparison at the true run rate, reviewed at the Class Thirty-Two monthly, not a panic migration off one surprising invoice. The sentence that keeps it honest: per-run billing didn't overcharge you — it itemised something, and the first job is to read what.

Examination record · first attempt
0/4
Class Forty-One · Complete
Retain this much

Five things worth carrying out of this class

  1. A Function is code with a trigger — it does not run until an event wakes it, runs for the work, and disappears. Serverless means the servers are Microsoft's problem; the function is yours. You bring the function; Azure brings everything around it.
  2. The model is one trigger, the code, and zero-or-more bindings. The trigger wakes it (queue, Service Bus, timer, HTTP, blob); bindings carry data in and out declaratively, so the code is about the work, not the plumbing.
  3. The hosting plan is the decision that bites: Consumption (scale to zero, cheap, cold starts, ~10-min cap), Premium/Flex (pre-warmed, VNet, long runs), App Service plan (always on). Start on Consumption; move up only when a named requirement forces you.
  4. Functions are stateless, must be idempotent (at-least-once triggers), and should be short and single-purpose. State in memory is a bug that waits for the second instance.
  5. Multi-step workflows that wait or fan out want Durable Functions — an orchestrator that checkpoints state and survives restarts. Name it when the interviewer describes a process, not a single message.
Notes
  1. The Functions hosting-plan lineup is mid-evolution: Flex Consumption keeps scale-to-zero and per-execution billing while shrinking cold starts (with paid always-ready instances to remove them outright), and Microsoft's guidance now recommends it for new serverless apps while the classic Linux Consumption plan walks a retirement path. Names and exact limits shift release to release; treat the plan trade-offs in §3 as stable — scale-to-zero versus cold starts versus always-on — and check the current plan-comparison page for the specific numbers before you design.
  2. On classic Consumption the timeout default is five minutes, configurable up to a ten-minute hard ceiling — the default is the floor, not the cap. Flex Consumption and Premium default to thirty minutes and can be raised much further; Dedicated is effectively unbounded. Do not memorise a single number — memorise that serverless plans cap runs in minutes and that a job which needs longer is telling you something about its shape, which §4 and §5 are the answer to.
  3. This class teaches Azure Functions because it is Azure's serverless compute and the estate runs on it, but the model outranks the product: an event triggers a short, stateless, idempotent unit of work, and long workflows move to a checkpointed orchestrator. Meet AWS Lambda with Step Functions, Google Cloud Functions with Workflows, or Cloudflare Workers and you will find the same shape — learn triggers, bindings, statelessness, and orchestration here once, and the products become configuration.