Why you profile before you pick
When most teams link two applications, they start with a product: "we'll use Service Bus" or "let's put a Logic App in". Six months later they learn that the payload is 400 KB, a partner needs to call in over HTTPS, or nobody on the team can debug a workflow designer. The service wasn't bad. Nobody asked the questions first.
An integration profile is a short, standard record of what a single link between two systems needs. You fill it in once per link, before you look at a product page. Every later lesson in this course (each service's fits and limits, and the weighted scorecard) reads from this profile. Think of it as the requirements sheet a structural engineer asks for before choosing between steel and timber.
We'll build one for a real link: Shop (orders web app) → Warehouse (stock and dispatch system).
Distinction 1: synchronous or asynchronous
- Synchronous: the caller sends a request and waits for the answer before it carries on, as with an HTTP call to an API. Both systems must be up at the same moment, and the caller's speed is tied to the slowest system it calls. This is temporal coupling.
- Asynchronous: the caller hands over a message and moves on. The receiver handles it when it can, even minutes later or after it comes back from an outage. You give up the instant answer and gain the ability to survive the receiver's downtime.
A practical test: does the user on the screen need the result right now to continue? "Is this item in stock?" while they browse is synchronous. "Pick and pack this order" is asynchronous. The user only needs to know it was accepted.
Gotcha: long waits break synchronous calls. On Azure App Service, for example, a request that sends nothing back for 230 seconds is cut off by the front-end load balancer, and you can't change that limit. If the work can take minutes or days, write it down as a long-running process. That points you to asynchronous messaging or orchestration, not a longer timeout.
Distinction 2: commands or events
- A command asks one specific receiver to do something:
ReserveStock,ChargeCard. It's named as an instruction, the sender cares whether it succeeds, and there is usually exactly one handler. - An event says something has happened:
OrderPlaced,StockLow. It's named in the past tense. The publisher doesn't know or care who listens, and there may be zero, one or ten subscribers. That number is your fan-out.
The coupling difference is real. A command couples the sender to the receiver's capability ("I know Warehouse reserves stock"). An event couples the listeners to the publisher's facts, so the publisher can add a new subscriber (Analytics, Loyalty) without changing any code.
Pitfall: a command dressed up as an event, such as
PleaseReserveStockEvent. If the publisher breaks when nobody acts on it, it's a command. Name it honestly, because the choice of service follows from it.
Walkthrough: turn business numbers into technical numbers
People will tell you "about 20,000 orders a day". A service limit is stated per second and per message, so convert:
# sizing.py: turn business volumes into the numbers the profile needs
orders_per_day = 20_000
busy_hours = 10 # most orders arrive in a 10-hour window
peak_factor = 5 # sale days / lunchtime spike vs the average
avg_per_sec = orders_per_day / (busy_hours * 3600)
peak_per_sec = avg_per_sec * peak_factor
sample_payload_bytes = len(open("sample-order.json", "rb").read()) # measure, don't guess
print(f"average: {avg_per_sec:.2f} msg/s, peak: {peak_per_sec:.1f} msg/s")
print(f"payload: {sample_payload_bytes/1024:.1f} KB")
average: 0.56 msg/s, peak: 2.8 msg/s
payload: 6.3 KB
Measure the payload from a real sample, and check the biggest one too, such as an order with 300 lines. Size limits differ a lot across services, so size is often the first filter. As dated examples from the docs (October 2026): Queue Storage messages are capped at 64 KB, Service Bus Standard at 256 KB, and Event Grid events at 1 MB (charged in 64 KB increments above 64 KB). A 6 KB order fits all three. A 2 MB PDF attachment fits none of them, so you'd store the file and send a link to it.
The profile itself
Keep it as a file in the repo next to the code, so it gets reviewed and versioned:
# integration-profile: shop-to-warehouse.yaml
link: Shop -> Warehouse (order fulfilment)
interaction: asynchronous # user only needs "order accepted"
message_kind: command # ReserveAndDispatch, one handler
ordering_and_duplicates: TBD # filled in next level
payload: { typical_kb: 6.3, max_kb: 40 }
volume: { avg_per_sec: 0.6, peak_per_sec: 3, growth_2y: x3 }
latency_acceptable: 30s end-to-end # warehouse picks in batches anyway
fan_out: 1 now; Analytics + Loyalty want OrderPlaced (event) next year
long_running: yes, dispatch confirmation can take 2 days
partners_saas: courier API (REST, OAuth2) for dispatch labels
api_consumers: none external for this link
security: private network only; managed identities, no shared keys
team_skills: strong C#/.NET, no workflow designer experience, 1 on-call engineer
cost_model: pay per use preferred; no budget for always-on capacity yet
The last two lines are constraints, just as real as payload size. The cost model is either pay per use (you're billed per operation, message or action and pay little when idle) or reserved capacity (a fixed hourly price for dedicated resources, predictable at scale, paid even when idle). Many Azure services offer both. Logic Apps Consumption bills each operation run, while Logic Apps Standard bills for a hosting plan whether or not workflows run. Service Bus Basic and Standard charge per operation, while Premium charges per messaging unit per hour.
Best practice: write "team_skills" honestly. A technically perfect choice that your one on-call engineer can't debug at 3 a.m. is the wrong choice.
Reading the profile
This link is asynchronous and command-shaped, small, low volume, tolerant of latency, long-running and pay-per-use. That's already enough to rule things out: a synchronous API call is wrong, and so is a high-throughput streaming platform. The note on future fan-out tells you an event (OrderPlaced) will sit alongside the command later. You'll score real candidates against this file in later levels.
Key takeaways
- Fill in one profile per link before you look at any product. Every later choice reads from it.
- Synchronous means both sides must be up together (temporal coupling). Asynchronous trades the instant answer for resilience.
- Commands are instructions to one handler. Events are past-tense facts with any number of subscribers (fan-out).
- Turn business volumes into peak messages per second, and measure real payloads. Size limits (64 KB, 256 KB, 1 MB) are often the first filter.
- Write down long-running work, partners, security, team skills and cost model (pay per use vs reserved) as constraints.