The HTTP call failed with status code: @{actions('HTTP_Action').outputs.statusCode}
" + } + }, + "runAfter": { + "Log_Error": ["Succeeded"] + } + } + }, + "runAfter": { + "HTTP_Action": ["Failed", "TimedOut"] + } + } +} +``` + +### 4. Expressions and Functions + +- **Use built-in expression functions** to transform data +- **Keep expressions concise and readable** +- **Document complex expressions** with comments + +Common expression patterns: +- String manipulation: `concat()`, `replace()`, `substring()` +- Collection operations: `filter()`, `map()`, `select()` +- Conditional logic: `if()`, `and()`, `or()`, `equals()` +- Date/time manipulation: `formatDateTime()`, `addDays()` +- JSON handling: `json()`, `array()`, `createArray()` + +```json +"Set_Variable": { + "type": "SetVariable", + "inputs": { + "name": "formattedData", + "value": "@{map(body('Parse_JSON'), item => { + return { + id: item.id, + name: toUpper(item.name), + date: formatDateTime(item.timestamp, 'yyyy-MM-dd') + } + })}" + } +} +``` + +#### Using Expressions in Power Automate Conditions + +Power Automate supports advanced expressions in conditions to check multiple values. When working with complex logical conditions, use the following pattern: + +- For comparing a single value: Use the basic condition designer interface +- For multiple conditions: Use advanced expressions in advanced mode + +Common logical expression functions for conditions in Power Automate: + +| Expression | Description | Example | +|------------|-------------|---------| +| `and` | Returns true if both arguments are true | `@and(equals(item()?['Status'], 'completed'), equals(item()?['Assigned'], 'John'))` | +| `or` | Returns true if either argument is true | `@or(equals(item()?['Status'], 'completed'), equals(item()?['Status'], 'unnecessary'))` | +| `equals` | Checks if values are equal | `@equals(item()?['Status'], 'blocked')` | +| `greater` | Checks if first value is greater than second | `@greater(item()?['Due'], item()?['Paid'])` | +| `less` | Checks if first value is less than second | `@less(item()?['dueDate'], addDays(utcNow(),1))` | +| `empty` | Checks if object, array or string is empty | `@empty(item()?['Status'])` | +| `not` | Returns opposite of a boolean value | `@not(contains(item()?['Status'], 'Failed'))` | + +Example: Check if a status is "completed" OR "unnecessary": +``` +@or(equals(item()?['Status'], 'completed'), equals(item()?['Status'], 'unnecessary')) +``` + +Example: Check if status is "blocked" AND assigned to specific person: +``` +@and(equals(item()?['Status'], 'blocked'), equals(item()?['Assigned'], 'John Wonder')) +``` + +Example: Check if a payment is overdue AND incomplete: +``` +@and(greater(item()?['Due'], item()?['Paid']), less(item()?['dueDate'], utcNow())) +``` + +**Note:** In Power Automate, when accessing dynamic values from previous steps in expressions, use the syntax `item()?['PropertyName']` to safely access properties in a collection. + +### 5. Parameters and Variables + +- **Parameterize your workflows** for reusability across environments +- **Use variables for temporary values** within a workflow +- **Define clear parameter schemas** with default values and descriptions + +```json +"parameters": { + "apiEndpoint": { + "type": "string", + "defaultValue": "https://api.dev.example.com", + "metadata": { + "description": "The base URL for the API endpoint" + } + } +}, +"variables": { + "requestId": "@{guid()}", + "processedItems": [] +} +``` + +### 6. Control Flow + +- **Use conditions** for branching logic +- **Implement parallel branches** for independent operations +- **Use foreach loops** with reasonable batch sizes for collections +- **Apply until loops** with proper exit conditions + +```json +"Process_Items": { + "type": "Foreach", + "foreach": "@body('Get_Items')", + "actions": { + "Process_Single_Item": { + "type": "Scope", + "actions": { } + } + }, + "runAfter": { + "Get_Items": ["Succeeded"] + }, + "runtimeConfiguration": { + "concurrency": { + "repetitions": 10 + } + } +} +``` + +### 7. Content and Message Handling + +- **Validate message schemas** to ensure data integrity +- **Implement proper content type handling** +- **Use Parse JSON actions** to work with structured data + +```json +"Parse_Response": { + "type": "ParseJson", + "inputs": { + "content": "@body('HTTP_Request')", + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { } + } + } + } + } + } +} +``` + +### 8. Security Best Practices + +- **Use managed identities** when possible +- **Store secrets in Key Vault** +- **Implement least privilege access** for connections +- **Secure API endpoints** with authentication +- **Implement IP restrictions** for HTTP triggers +- **Apply data encryption** for sensitive data in parameters and messages +- **Use Azure RBAC** to control access to Logic Apps resources +- **Conduct regular security reviews** of workflows and connections + +```json +"Get_Secret": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['keyvault']['connectionId']" + } + }, + "method": "get", + "path": "/secrets/@{encodeURIComponent('apiKey')}/value" + } +}, +"Call_Protected_API": { + "type": "Http", + "inputs": { + "method": "POST", + "uri": "https://api.example.com/protected", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer @{body('Get_Secret')?['value']}" + }, + "body": { + "data": "@variables('processedData')" + } + }, + "authentication": { + "type": "ManagedServiceIdentity" + }, + "runAfter": { + "Get_Secret": ["Succeeded"] + } +} +``` + +## Performance Optimization + +- **Minimize unnecessary actions** +- **Use batch operations** when available +- **Optimize expressions** to reduce complexity +- **Configure appropriate timeout values** +- **Implement pagination** for large data sets +- **Implement concurrency control** for parallelizable operations + +```json +"Process_Items": { + "type": "Foreach", + "foreach": "@body('Get_Items')", + "actions": { + "Process_Single_Item": { + "type": "Scope", + "actions": { } + } + }, + "runAfter": { + "Get_Items": ["Succeeded"] + }, + "runtimeConfiguration": { + "concurrency": { + "repetitions": 10 + } + } +} +``` + +### Workflow Design Best Practices + +- **Limit workflows to 50 actions or less** for optimal designer performance +- **Split complex business logic** into multiple smaller workflows when necessary +- **Use deployment slots** for mission-critical logic apps that require zero downtime deployments +- **Avoid hardcoded properties** in trigger and action definitions +- **Add descriptive comments** to provide context about trigger and action definitions +- **Use built-in operations** when available instead of shared connectors for better performance +- **Use an Integration Account** for B2B scenarios and EDI message processing +- **Reuse workflow templates** for standard patterns across your organization +- **Avoid deep nesting** of scopes and actions to maintain readability + +### Monitoring and Observability + +- **Configure diagnostic settings** to capture workflow runs and metrics +- **Add tracking IDs** to correlate related workflow runs +- **Implement comprehensive logging** with appropriate detail levels +- **Set up alerts** for workflow failures and performance degradation +- **Use Application Insights** for end-to-end tracing and monitoring + +## Platform Types and Considerations + +### Azure Logic Apps vs Power Automate + +While Azure Logic Apps and Power Automate share the same underlying workflow engine and language, they have different target audiences and capabilities: + +- **Power Automate**: + - User-friendly interface for business users + - Part of the Power Platform ecosystem + - Integration with Microsoft 365 and Dynamics 365 + - Desktop flow capabilities for UI automation + +- **Azure Logic Apps**: + - Enterprise-grade integration platform + - Developer-focused with advanced capabilities + - Deeper Azure service integration + - More extensive monitoring and operations capabilities + +### Logic App Types + +#### Consumption Logic Apps +- Pay-per-execution pricing model +- Serverless architecture +- Suitable for variable or unpredictable workloads + +#### Standard Logic Apps +- Fixed pricing based on App Service Plan +- Predictable performance +- Local development support +- Integration with VNets + +#### Integration Service Environment (ISE) +- Dedicated deployment environment +- Higher throughput and longer execution durations +- Direct access to VNet resources +- Isolated runtime environment + +### Power Automate License Types +- **Power Automate per user plan**: For individual users +- **Power Automate per flow plan**: For specific workflows +- **Power Automate Process plan**: For RPA capabilities +- **Power Automate included with Office 365**: Limited capabilities for Office 365 users + +## Common Integration Patterns + +### Architectural Patterns +- **Mediator Pattern**: Use Logic Apps/Power Automate as an orchestration layer between systems +- **Content-Based Routing**: Route messages based on content to different destinations +- **Message Transformation**: Transform messages between formats (JSON, XML, EDI, etc.) +- **Scatter-Gather**: Distribute work in parallel and aggregate results +- **Protocol Bridging**: Connect systems with different protocols (REST, SOAP, FTP, etc.) +- **Claim Check**: Store large payloads externally in blob storage or databases +- **Saga Pattern**: Manage distributed transactions with compensating actions for failures +- **Choreography Pattern**: Coordinate multiple services without a central orchestrator + +### Action Patterns +- **Asynchronous Processing Pattern**: For long-running operations + ```json + "LongRunningAction": { + "type": "Http", + "inputs": { + "method": "POST", + "uri": "https://api.example.com/longrunning", + "body": { "data": "@triggerBody()" } + }, + "retryPolicy": { + "type": "fixed", + "count": 3, + "interval": "PT30S" + } + } + ``` + +- **Webhook Pattern**: For callback-based processing + ```json + "WebhookAction": { + "type": "ApiConnectionWebhook", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['servicebus']['connectionId']" + } + }, + "body": { + "content": "@triggerBody()" + }, + "path": "/subscribe/topics/@{encodeURIComponent('mytopic')}/subscriptions/@{encodeURIComponent('mysubscription')}" + } + } + ``` + +### Enterprise Integration Patterns +- **B2B Message Exchange**: Exchange EDI documents between trading partners (AS2, X12, EDIFACT) +- **Integration Account**: Use for storing and managing B2B artifacts (agreements, schemas, maps) +- **Rules Engine**: Implement complex business rules using the Azure Logic Apps Rules Engine +- **Message Validation**: Validate messages against schemas for compliance and data integrity +- **Transaction Processing**: Process business transactions with compensating transactions for rollback + +## DevOps and CI/CD for Logic Apps + +### Source Control and Versioning + +- **Store Logic App definitions in source control** (Git, Azure DevOps, GitHub) +- **Use ARM templates** for deployment to multiple environments +- **Implement branching strategies** appropriate for your release cadence +- **Version your Logic Apps** using tags or version properties + +### Automated Deployment + +- **Use Azure DevOps pipelines** or GitHub Actions for automated deployments +- **Implement parameterization** for environment-specific values +- **Use deployment slots** for zero-downtime deployments +- **Include post-deployment validation** tests in your CI/CD pipeline + +```yaml +# Example Azure DevOps YAML pipeline for Logic App deployment +trigger: + branches: + include: + - main + - release/* + +pool: + vmImage: 'ubuntu-latest' + +steps: +- task: AzureResourceManagerTemplateDeployment@3 + inputs: + deploymentScope: 'Resource Group' + azureResourceManagerConnection: 'Your-Azure-Connection' + subscriptionId: '$(subscriptionId)' + action: 'Create Or Update Resource Group' + resourceGroupName: '$(resourceGroupName)' + location: '$(location)' + templateLocation: 'Linked artifact' + csmFile: '$(System.DefaultWorkingDirectory)/arm-templates/logicapp-template.json' + csmParametersFile: '$(System.DefaultWorkingDirectory)/arm-templates/logicapp-parameters-$(Environment).json' + deploymentMode: 'Incremental' +``` + +## Cross-Platform Considerations + +When working with both Azure Logic Apps and Power Automate: + +- **Export/Import Compatibility**: Flows can be exported from Power Automate and imported into Logic Apps, but some modifications may be required +- **Connector Differences**: Some connectors are available in one platform but not the other +- **Environment Isolation**: Power Automate environments provide isolation and may have different policies +- **ALM Practices**: Consider using Azure DevOps for Logic Apps and Solutions for Power Automate + +### Migration Strategies + +- **Assessment**: Evaluate complexity and suitability for migration +- **Connector Mapping**: Map connectors between platforms and identify gaps +- **Testing Strategy**: Implement parallel testing before cutover +- **Documentation**: Document all configuration changes for reference + +```json +// Example Power Platform solution structure for Power Automate flows +{ + "SolutionName": "MyEnterpriseFlows", + "Version": "1.0.0", + "Flows": [ + { + "Name": "OrderProcessingFlow", + "Type": "Microsoft.Flow/flows", + "Properties": { + "DisplayName": "Order Processing Flow", + "DefinitionData": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "triggers": { + "When_a_new_order_is_created": { + "type": "ApiConnectionWebhook", + "inputs": { + "host": { + "connectionName": "shared_commondataserviceforapps", + "operationId": "SubscribeWebhookTrigger", + "apiId": "/providers/Microsoft.PowerApps/apis/shared_commondataserviceforapps" + } + } + } + }, + "actions": { + // Actions would be defined here + } + } + } + } + ] +} +``` + +## Practical Logic App Examples + +### HTTP Request Handler with API Integration + +This example demonstrates a Logic App that accepts an HTTP request, validates the input data, calls an external API, transforms the response, and returns a formatted result. + +```json +{ + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": { + "Validate_Input": { + "type": "If", + "expression": { + "and": [ + { + "not": { + "equals": [ + "@triggerBody()?['customerId']", + null + ] + } + }, + { + "not": { + "equals": [ + "@triggerBody()?['requestType']", + null + ] + } + } + ] + }, + "actions": { + "Get_Customer_Data": { + "type": "Http", + "inputs": { + "method": "GET", + "uri": "https://api.example.com/customers/@{triggerBody()?['customerId']}", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer @{body('Get_API_Key')?['value']}" + } + }, + "runAfter": { + "Get_API_Key": [ + "Succeeded" + ] + } + }, + "Get_API_Key": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['keyvault']['connectionId']" + } + }, + "method": "get", + "path": "/secrets/@{encodeURIComponent('apiKey')}/value" + } + }, + "Parse_Customer_Response": { + "type": "ParseJson", + "inputs": { + "content": "@body('Get_Customer_Data')", + "schema": { + "type": "object", + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "email": { "type": "string" }, + "status": { "type": "string" }, + "createdDate": { "type": "string" }, + "orders": { + "type": "array", + "items": { + "type": "object", + "properties": { + "orderId": { "type": "string" }, + "orderDate": { "type": "string" }, + "amount": { "type": "number" } + } + } + } + } + } + }, + "runAfter": { + "Get_Customer_Data": [ + "Succeeded" + ] + } + }, + "Switch_Request_Type": { + "type": "Switch", + "expression": "@triggerBody()?['requestType']", + "cases": { + "Profile": { + "actions": { + "Prepare_Profile_Response": { + "type": "SetVariable", + "inputs": { + "name": "responsePayload", + "value": { + "customerId": "@body('Parse_Customer_Response')?['id']", + "customerName": "@body('Parse_Customer_Response')?['name']", + "email": "@body('Parse_Customer_Response')?['email']", + "status": "@body('Parse_Customer_Response')?['status']", + "memberSince": "@formatDateTime(body('Parse_Customer_Response')?['createdDate'], 'yyyy-MM-dd')" + } + } + } + } + }, + "OrderSummary": { + "actions": { + "Calculate_Order_Statistics": { + "type": "Compose", + "inputs": { + "totalOrders": "@length(body('Parse_Customer_Response')?['orders'])", + "totalSpent": "@sum(body('Parse_Customer_Response')?['orders'], item => item.amount)", + "averageOrderValue": "@if(greater(length(body('Parse_Customer_Response')?['orders']), 0), div(sum(body('Parse_Customer_Response')?['orders'], item => item.amount), length(body('Parse_Customer_Response')?['orders'])), 0)", + "lastOrderDate": "@if(greater(length(body('Parse_Customer_Response')?['orders']), 0), max(body('Parse_Customer_Response')?['orders'], item => item.orderDate), '')" + } + }, + "Prepare_Order_Response": { + "type": "SetVariable", + "inputs": { + "name": "responsePayload", + "value": { + "customerId": "@body('Parse_Customer_Response')?['id']", + "customerName": "@body('Parse_Customer_Response')?['name']", + "orderStats": "@outputs('Calculate_Order_Statistics')" + } + }, + "runAfter": { + "Calculate_Order_Statistics": [ + "Succeeded" + ] + } + } + } + } + }, + "default": { + "actions": { + "Set_Default_Response": { + "type": "SetVariable", + "inputs": { + "name": "responsePayload", + "value": { + "error": "Invalid request type specified", + "validTypes": [ + "Profile", + "OrderSummary" + ] + } + } + } + } + }, + "runAfter": { + "Parse_Customer_Response": [ + "Succeeded" + ] + } + }, + "Log_Successful_Request": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['applicationinsights']['connectionId']" + } + }, + "method": "post", + "body": { + "LogType": "ApiRequestSuccess", + "CustomerId": "@triggerBody()?['customerId']", + "RequestType": "@triggerBody()?['requestType']", + "ProcessingTime": "@workflow()['run']['duration']" + } + }, + "runAfter": { + "Switch_Request_Type": [ + "Succeeded" + ] + } + }, + "Return_Success_Response": { + "type": "Response", + "kind": "Http", + "inputs": { + "statusCode": 200, + "body": "@variables('responsePayload')", + "headers": { + "Content-Type": "application/json" + } + }, + "runAfter": { + "Log_Successful_Request": [ + "Succeeded" + ] + } + } + }, + "else": { + "actions": { + "Return_Validation_Error": { + "type": "Response", + "kind": "Http", + "inputs": { + "statusCode": 400, + "body": { + "error": "Invalid request", + "message": "Request must include customerId and requestType", + "timestamp": "@utcNow()" + } + } + } + } + }, + "runAfter": { + "Initialize_Response_Variable": [ + "Succeeded" + ] + } + }, + "Initialize_Response_Variable": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "responsePayload", + "type": "object", + "value": {} + } + ] + } + } + }, + "contentVersion": "1.0.0.0", + "outputs": {}, + "parameters": { + "$connections": { + "defaultValue": {}, + "type": "Object" + } + }, + "triggers": { + "manual": { + "type": "Request", + "kind": "Http", + "inputs": { + "schema": { + "type": "object", + "properties": { + "customerId": { + "type": "string" + }, + "requestType": { + "type": "string", + "enum": [ + "Profile", + "OrderSummary" + ] + } + } + } + } + } + } + }, + "parameters": { + "$connections": { + "value": { + "keyvault": { + "connectionId": "/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/connections/keyvault", + "connectionName": "keyvault", + "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/{location}/managedApis/keyvault" + }, + "applicationinsights": { + "connectionId": "/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/connections/applicationinsights", + "connectionName": "applicationinsights", + "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/{location}/managedApis/applicationinsights" + } + } + } + } +} +``` + +### Event-Driven Process with Error Handling + +This example demonstrates a Logic App that processes events from Azure Service Bus, handles the message processing with robust error handling, and implements the retry pattern for resilience. + +```json +{ + "definition": { + "$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#", + "actions": { + "Parse_Message": { + "type": "ParseJson", + "inputs": { + "content": "@triggerBody()?['ContentData']", + "schema": { + "type": "object", + "properties": { + "eventId": { "type": "string" }, + "eventType": { "type": "string" }, + "eventTime": { "type": "string" }, + "dataVersion": { "type": "string" }, + "data": { + "type": "object", + "properties": { + "orderId": { "type": "string" }, + "customerId": { "type": "string" }, + "items": { + "type": "array", + "items": { + "type": "object", + "properties": { + "productId": { "type": "string" }, + "quantity": { "type": "integer" }, + "unitPrice": { "type": "number" } + } + } + } + } + } + } + } + }, + "runAfter": {} + }, + "Try_Process_Order": { + "type": "Scope", + "actions": { + "Get_Customer_Details": { + "type": "Http", + "inputs": { + "method": "GET", + "uri": "https://api.example.com/customers/@{body('Parse_Message')?['data']?['customerId']}", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer @{body('Get_API_Key')?['value']}" + } + }, + "runAfter": { + "Get_API_Key": [ + "Succeeded" + ] + }, + "retryPolicy": { + "type": "exponential", + "count": 5, + "interval": "PT10S", + "minimumInterval": "PT5S", + "maximumInterval": "PT1H" + } + }, + "Get_API_Key": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['keyvault']['connectionId']" + } + }, + "method": "get", + "path": "/secrets/@{encodeURIComponent('apiKey')}/value" + } + }, + "Validate_Stock": { + "type": "Foreach", + "foreach": "@body('Parse_Message')?['data']?['items']", + "actions": { + "Check_Product_Stock": { + "type": "Http", + "inputs": { + "method": "GET", + "uri": "https://api.example.com/inventory/@{items('Validate_Stock')?['productId']}", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer @{body('Get_API_Key')?['value']}" + } + }, + "retryPolicy": { + "type": "fixed", + "count": 3, + "interval": "PT15S" + } + }, + "Verify_Availability": { + "type": "If", + "expression": { + "and": [ + { + "greater": [ + "@body('Check_Product_Stock')?['availableStock']", + "@items('Validate_Stock')?['quantity']" + ] + } + ] + }, + "actions": { + "Add_To_Valid_Items": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "validItems", + "value": { + "productId": "@items('Validate_Stock')?['productId']", + "quantity": "@items('Validate_Stock')?['quantity']", + "unitPrice": "@items('Validate_Stock')?['unitPrice']", + "availableStock": "@body('Check_Product_Stock')?['availableStock']" + } + } + } + }, + "else": { + "actions": { + "Add_To_Invalid_Items": { + "type": "AppendToArrayVariable", + "inputs": { + "name": "invalidItems", + "value": { + "productId": "@items('Validate_Stock')?['productId']", + "requestedQuantity": "@items('Validate_Stock')?['quantity']", + "availableStock": "@body('Check_Product_Stock')?['availableStock']", + "reason": "Insufficient stock" + } + } + } + } + }, + "runAfter": { + "Check_Product_Stock": [ + "Succeeded" + ] + } + } + }, + "runAfter": { + "Get_Customer_Details": [ + "Succeeded" + ] + } + }, + "Check_Order_Validity": { + "type": "If", + "expression": { + "and": [ + { + "equals": [ + "@length(variables('invalidItems'))", + 0 + ] + }, + { + "greater": [ + "@length(variables('validItems'))", + 0 + ] + } + ] + }, + "actions": { + "Process_Valid_Order": { + "type": "Http", + "inputs": { + "method": "POST", + "uri": "https://api.example.com/orders", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer @{body('Get_API_Key')?['value']}" + }, + "body": { + "orderId": "@body('Parse_Message')?['data']?['orderId']", + "customerId": "@body('Parse_Message')?['data']?['customerId']", + "customerName": "@body('Get_Customer_Details')?['name']", + "items": "@variables('validItems')", + "processedTime": "@utcNow()", + "eventId": "@body('Parse_Message')?['eventId']" + } + } + }, + "Send_Order_Confirmation": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail", + "body": { + "To": "@body('Get_Customer_Details')?['email']", + "Subject": "Order Confirmation: @{body('Parse_Message')?['data']?['orderId']}", + "Body": "Dear @{body('Get_Customer_Details')?['name']},
Your order has been successfully processed.
Order ID: @{body('Parse_Message')?['data']?['orderId']}
Thank you for your business!
", + "Importance": "Normal", + "IsHtml": true + } + }, + "runAfter": { + "Process_Valid_Order": [ + "Succeeded" + ] + } + }, + "Complete_Message": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['servicebus']['connectionId']" + } + }, + "method": "post", + "path": "/messages/complete", + "body": { + "lockToken": "@triggerBody()?['LockToken']", + "sessionId": "@triggerBody()?['SessionId']", + "queueName": "@parameters('serviceBusQueueName')" + } + }, + "runAfter": { + "Send_Order_Confirmation": [ + "Succeeded" + ] + } + } + }, + "else": { + "actions": { + "Send_Invalid_Stock_Notification": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail", + "body": { + "To": "@body('Get_Customer_Details')?['email']", + "Subject": "Order Cannot Be Processed: @{body('Parse_Message')?['data']?['orderId']}", + "Body": "Dear @{body('Get_Customer_Details')?['name']},
We regret to inform you that your order cannot be processed due to insufficient stock for the following items:
@{join(variables('invalidItems'), '
')}
Please adjust your order and try again.
", + "Importance": "High", + "IsHtml": true + } + } + }, + "Dead_Letter_Message": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['servicebus']['connectionId']" + } + }, + "method": "post", + "path": "/messages/deadletter", + "body": { + "lockToken": "@triggerBody()?['LockToken']", + "sessionId": "@triggerBody()?['SessionId']", + "queueName": "@parameters('serviceBusQueueName')", + "deadLetterReason": "InsufficientStock", + "deadLetterDescription": "Order contained items with insufficient stock" + } + }, + "runAfter": { + "Send_Invalid_Stock_Notification": [ + "Succeeded" + ] + } + } + } + }, + "runAfter": { + "Validate_Stock": [ + "Succeeded" + ] + } + } + }, + "runAfter": { + "Initialize_Variables": [ + "Succeeded" + ] + } + }, + "Initialize_Variables": { + "type": "InitializeVariable", + "inputs": { + "variables": [ + { + "name": "validItems", + "type": "array", + "value": [] + }, + { + "name": "invalidItems", + "type": "array", + "value": [] + } + ] + }, + "runAfter": { + "Parse_Message": [ + "Succeeded" + ] + } + }, + "Handle_Process_Error": { + "type": "Scope", + "actions": { + "Log_Error_Details": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['applicationinsights']['connectionId']" + } + }, + "method": "post", + "body": { + "LogType": "OrderProcessingError", + "EventId": "@body('Parse_Message')?['eventId']", + "OrderId": "@body('Parse_Message')?['data']?['orderId']", + "CustomerId": "@body('Parse_Message')?['data']?['customerId']", + "ErrorDetails": "@result('Try_Process_Order')", + "Timestamp": "@utcNow()" + } + } + }, + "Abandon_Message": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['servicebus']['connectionId']" + } + }, + "method": "post", + "path": "/messages/abandon", + "body": { + "lockToken": "@triggerBody()?['LockToken']", + "sessionId": "@triggerBody()?['SessionId']", + "queueName": "@parameters('serviceBusQueueName')" + } + }, + "runAfter": { + "Log_Error_Details": [ + "Succeeded" + ] + } + }, + "Send_Alert_To_Operations": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['office365']['connectionId']" + } + }, + "method": "post", + "path": "/v2/Mail", + "body": { + "To": "operations@example.com", + "Subject": "Order Processing Error: @{body('Parse_Message')?['data']?['orderId']}", + "Body": "An error occurred while processing an order:
Order ID: @{body('Parse_Message')?['data']?['orderId']}
Customer ID: @{body('Parse_Message')?['data']?['customerId']}
Error: @{result('Try_Process_Order')}
", + "Importance": "High", + "IsHtml": true + } + }, + "runAfter": { + "Abandon_Message": [ + "Succeeded" + ] + } + } + }, + "runAfter": { + "Try_Process_Order": [ + "Failed", + "TimedOut" + ] + } + } + }, + "contentVersion": "1.0.0.0", + "outputs": {}, + "parameters": { + "$connections": { + "defaultValue": {}, + "type": "Object" + }, + "serviceBusQueueName": { + "type": "string", + "defaultValue": "orders" + } + }, + "triggers": { + "When_a_message_is_received_in_a_queue": { + "type": "ApiConnectionWebhook", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['servicebus']['connectionId']" + } + }, + "body": { + "isSessionsEnabled": true + }, + "path": "/subscriptionListener", + "queries": { + "queueName": "@parameters('serviceBusQueueName')", + "subscriptionType": "Main" + } + } + } + } + }, + "parameters": { + "$connections": { + "value": { + "keyvault": { + "connectionId": "/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/connections/keyvault", + "connectionName": "keyvault", + "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/{location}/managedApis/keyvault" + }, + "servicebus": { + "connectionId": "/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/connections/servicebus", + "connectionName": "servicebus", + "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/{location}/managedApis/servicebus" + }, + "office365": { + "connectionId": "/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/connections/office365", + "connectionName": "office365", + "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/{location}/managedApis/office365" + }, + "applicationinsights": { + "connectionId": "/subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Web/connections/applicationinsights", + "connectionName": "applicationinsights", + "id": "/subscriptions/{subscription-id}/providers/Microsoft.Web/locations/{location}/managedApis/applicationinsights" + } + } + } + } +} +``` + +## Advanced Exception Handling and Monitoring + +### Comprehensive Exception Handling Strategy + +Implement a multi-layered exception handling approach for robust workflows: + +1. **Preventative Measures**: + - Use schema validation for all incoming messages + - Implement defensive expression evaluations using `coalesce()` and `?` operators + - Add pre-condition checks before critical operations + +2. **Runtime Error Handling**: + - Use structured error handling scopes with nested try/catch patterns + - Implement circuit breaker patterns for external dependencies + - Capture and handle specific error types differently + +```json +"Process_With_Comprehensive_Error_Handling": { + "type": "Scope", + "actions": { + "Try_Primary_Action": { + "type": "Scope", + "actions": { + "Main_Operation": { + "type": "Http", + "inputs": { "method": "GET", "uri": "https://api.example.com/resource" } + } + } + }, + "Handle_Connection_Errors": { + "type": "Scope", + "actions": { + "Log_Connection_Error": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['loganalytics']['connectionId']" + } + }, + "method": "post", + "body": { + "LogType": "ConnectionError", + "ErrorCategory": "Network", + "StatusCode": "@{result('Try_Primary_Action')?['outputs']?['Main_Operation']?['statusCode']}", + "ErrorMessage": "@{result('Try_Primary_Action')?['error']?['message']}" + } + } + }, + "Invoke_Fallback_Endpoint": { + "type": "Http", + "inputs": { "method": "GET", "uri": "https://fallback-api.example.com/resource" } + } + }, + "runAfter": { + "Try_Primary_Action": ["Failed"] + } + }, + "Handle_Business_Logic_Errors": { + "type": "Scope", + "actions": { + "Parse_Error_Response": { + "type": "ParseJson", + "inputs": { + "content": "@outputs('Try_Primary_Action')?['Main_Operation']?['body']", + "schema": { + "type": "object", + "properties": { + "errorCode": { "type": "string" }, + "errorMessage": { "type": "string" } + } + } + } + }, + "Switch_On_Error_Type": { + "type": "Switch", + "expression": "@body('Parse_Error_Response')?['errorCode']", + "cases": { + "ResourceNotFound": { + "actions": { "Create_Resource": { "type": "Http", "inputs": {} } } + }, + "ValidationError": { + "actions": { "Resubmit_With_Defaults": { "type": "Http", "inputs": {} } } + }, + "PermissionDenied": { + "actions": { "Elevate_Permissions": { "type": "Http", "inputs": {} } } + } + }, + "default": { + "actions": { "Send_To_Support_Queue": { "type": "ApiConnection", "inputs": {} } } + } + } + }, + "runAfter": { + "Try_Primary_Action": ["Succeeded"] + } + } + } +} +``` + +3. **Centralized Error Logging**: + - Create a dedicated Logic App for error handling that other workflows can call + - Log errors with correlation IDs for traceability across systems + - Categorize errors by type and severity for better analysis + +### Advanced Monitoring Architecture + +Implement a comprehensive monitoring strategy that covers: + +1. **Operational Monitoring**: + - **Health Probes**: Create dedicated health check workflows + - **Heartbeat Patterns**: Implement periodic check-ins to verify system health + - **Dead Letter Handling**: Process and analyze failed messages + +2. **Business Process Monitoring**: + - **Business Metrics**: Track key business KPIs (order processing times, approval rates) + - **SLA Monitoring**: Measure performance against service level agreements + - **Correlated Tracing**: Implement end-to-end transaction tracking + +3. **Alerting Strategy**: + - **Multi-channel Alerts**: Configure alerts to appropriate channels (email, SMS, Teams) + - **Severity-based Routing**: Route alerts based on business impact + - **Alert Correlation**: Group related alerts to prevent alert fatigue + +```json +"Monitor_Transaction_SLA": { + "type": "Scope", + "actions": { + "Calculate_Processing_Time": { + "type": "Compose", + "inputs": "@{div(sub(ticks(utcNow()), ticks(triggerBody()?['startTime'])), 10000000)}" + }, + "Check_SLA_Breach": { + "type": "If", + "expression": "@greater(outputs('Calculate_Processing_Time'), parameters('slaThresholdSeconds'))", + "actions": { + "Log_SLA_Breach": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['loganalytics']['connectionId']" + } + }, + "method": "post", + "body": { + "LogType": "SLABreach", + "TransactionId": "@{triggerBody()?['transactionId']}", + "ProcessingTimeSeconds": "@{outputs('Calculate_Processing_Time')}", + "SLAThresholdSeconds": "@{parameters('slaThresholdSeconds')}", + "BreachSeverity": "@if(greater(outputs('Calculate_Processing_Time'), mul(parameters('slaThresholdSeconds'), 2)), 'Critical', 'Warning')" + } + } + }, + "Send_SLA_Alert": { + "type": "ApiConnection", + "inputs": { + "host": { + "connection": { + "name": "@parameters('$connections')['teams']['connectionId']" + } + }, + "method": "post", + "body": { + "notificationTitle": "SLA Breach Alert", + "message": "Transaction @{triggerBody()?['transactionId']} exceeded SLA by @{sub(outputs('Calculate_Processing_Time'), parameters('slaThresholdSeconds'))} seconds", + "channelId": "@{if(greater(outputs('Calculate_Processing_Time'), mul(parameters('slaThresholdSeconds'), 2)), parameters('criticalAlertChannelId'), parameters('warningAlertChannelId'))}" + } + } + } + } + } + } +} +``` + +## API Management Integration + +Integrate Logic Apps with Azure API Management for enhanced security, governance, and management: + +### API Management Frontend + +- **Expose Logic Apps via API Management**: + - Create API definitions for Logic App HTTP triggers + - Apply consistent URL structures and versioning + - Implement API policies for security and transformation + +### Policy Templates for Logic Apps + +```xml + +