Master Blueprint: Event-Driven Automation with Logic Apps & Container App Jobs

A step-by-step guide for building an event-driven security scanner. We'll build and test each component before moving to the next.
The Architecture
[Logic App] → [Service Bus Queue] → [Container App Job]
(trigger) (message queue) (worker)How it works:
Step 1: Create Service Bus & Logic App
First, we set up the message queue and the trigger.
1.1 Create the Service Bus
scan-queue1.2 Create the Logic App & Workflow
- First time: it asks for a connection - paste your connection string from step 1.1
- Queue name: scan-queue
- Content: {"target": "https://example.com", "scanType": "full"}
1.3 Test It
scan-queue → Service Bus ExplorerMessage in the queue? Step 1 complete.
Step 2: Build the Worker & Push to ACR
Now we create the container that processes messages.
2.1 Create Azure Container Registry
2.2 The Worker Code (Node.js)
Create a file index.js:
const { ServiceBusClient } = require("@azure/service-bus");
async function main() {
const sbClient = new ServiceBusClient(process.env.SB_CONNECTION);
const receiver = sbClient.createReceiver("scan-queue", {
receiveMode: "peekLock"
});
const messages = await receiver.receiveMessages(1, { maxWaitTimeInMs: 5000 });
if (messages.length > 0) {
const message = messages[0];
console.log("Processing:", message.body);
// Start a lock renewal loop for long-running jobs
const lockRenewalInterval = setInterval(async () => {
try {
await receiver.renewMessageLock(message);
console.log("Lock renewed");
} catch (err) {
console.error("Lock renewal failed:", err);
}
}, 60000); // Renew every 60 seconds
try {
// Your scan logic here
await runSecurityScan(message.body.target);
clearInterval(lockRenewalInterval);
await receiver.completeMessage(message);
console.log("Done - message completed");
} catch (err) {
clearInterval(lockRenewalInterval);
await receiver.abandonMessage(message);
console.error("Failed - message abandoned:", err);
}
} else {
console.log("No messages in queue");
}
await sbClient.close();
}
main();2.3 Create package.json
{
"name": "security-scanner",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@azure/service-bus": "^7.9.0"
}
}2.4 Create Dockerfile
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
CMD ["node", "index.js"]2.5 Build & Push to ACR
# Login to your registry
az acr login --name [acr-name]
# Build and push
docker build -t [acr-name].azurecr.io/security-scanner:v1 .
docker push [acr-name].azurecr.io/security-scanner:v1Step 3: Create the Container App Job
Now we create the job that KEDA will trigger when messages arrive.
3.1 Create Container Apps Environment
3.2 Create the Job
- Registry: select yours
- Image: security-scanner
- Tag: v1
- Authentication: Admin credentials
3.3 Configure Event Trigger & Secrets (during creation)
In the Event trigger section:
Scale rule:
service-bus-triggerscan-queue3.4 Add Environment Variable
In the Container section → Environment variables:
SB_CONNECTIONCreate the job.
Step 4: Test the Pipeline
4.1 First Test
4.2 What to Check in Logs
If you see these, your event-driven pipeline is working.
Summary
What we built:
You only pay for compute while scans are running.
For production: Switch to Managed Identity instead of connection strings (no credentials to manage).
Aziz Jarrar
Full Stack Engineer