Resubmissions in Azure Logic Apps often seem like a simple replay, but under the hood, Azure maintains a powerful tracking model that links every resubmitted run back to its original execution.
This post walks through a hands-on demo workflow that reveals how clientTrackingId, sourceHistoryName (SHN), and originHistoryName (OHN) work together to track and correlate resubmitted runs — whether you resubmit all or resume from a point of failure.
⚙️ Logic App Overview
The Logic App used in this demo — wf_rcv_http_resubmit_demo — is a stateful workflow built to demonstrate how Azure Logic Apps track and correlate resubmitted runs.
It exposes an HTTP trigger that accepts any JSON payload and passes it through a minimal processing pipeline:
-
Initialize Variable (
runInfo) – Captures key runtime properties such as:
Initializer snippet (original):
{
"type": "InitializeVariable",
"inputs": {
"variables": [
{
"name": "runInfo",
"type": "object",
"value": {
"trackingId": "@{trigger().trackingId}",
"clientTrackingId": "@{trigger().clientTrackingId}",
"runId": "@{workflow()['run']['name']}",
"originHistoryName": "@{trigger().originHistoryName}",
"originRunId": "@{trigger()?.originHistoryName}",
"sourceHistoryName": "@{trigger()?.sourceHistoryName}",
"isResubmission": "@not(empty(trigger()?.sourceHistoryName))",
"timestamp": "@{utcNow()}"
}
}
]
},
"runAfter": {}
}
-
C# Script (
randomness) – Simulates some lightweight logic execution (e.g., transformation or validation).
#r "Newtonsoft.Json"
#r "Microsoft.Azure.Workflows.Scripting"
using System;
using System.Threading.Tasks;
using System.Security.Cryptography; // optional but recommended
using Microsoft.Extensions.Logging;
using Microsoft.Azure.Workflows.Scripting;
using Newtonsoft.Json.Linq;
public static async Task<string> Run(WorkflowContext context, ILogger log)
{
// --- Trigger info ---
var triggerResult = await context.GetTriggerResults().ConfigureAwait(false);
string getFromTriggerOHN = triggerResult?.OriginHistoryName ?? "unknown";
string getFromTriggerSHN = triggerResult?.SourceHistoryName ?? ""; // empty when original run
bool isResubTrigger = !string.IsNullOrEmpty(getFromTriggerSHN); // <-- use the correct var
// --- From InitializeVariable action 'runDetails'
var ar = await context.GetActionResults("runDetails").ConfigureAwait(false);
var bodyToken = ar?.Outputs;
if (bodyToken == null) return "runDetails had no body";
// Treat the JSON as a dynamic object
dynamic c = bodyToken as JObject ?? JObject.Parse(bodyToken.ToString());
string runId = (string)c.runId ?? "unknown";
string originHistoryName = (string)c.originHistoryName ?? "unknown";
string originRunId = (string)c.originRunId ?? "null";
string sourceHistoryName = (string)c.sourceHistoryName ?? "null";
bool isResubFromVar = (bool?) c.isResubmission ?? false;
// --- Random failure: 60% original, 10% resub ---
int failThreshold = isResubFromVar ? 10 : 60;
// Prefer crypto RNG to avoid seed/retry issues
int n = RandomNumberGenerator.GetInt32(1, 101); // 1..100 inclusive
// int n = new Random().Next(1, 101); // fallback if crypto RNG unavailable
if (n <= failThreshold)
{
// simulate failure
int _ = n / 0;
}
string message =
$"n={n}; FailThreshold={failThreshold}; " +
$"IsResubmissionFromVar={isResubFromVar}; " +
$"sHN(Var)={sourceHistoryName}; " +
$"sHN(Trigger)={(string.IsNullOrEmpty(getFromTriggerSHN) ? "null" : getFromTriggerSHN)}; " +
$"IsResubmitInline={isResubTrigger}; " +
$"OHN(Trigger)={getFromTriggerOHN}; RunId={runId}";
return message;
}
-
Compose (
consolidatedResult) – Gathers all relevant values again usingtrigger()andworkflow()expressions, showing how each property behaves in both original and resubmitted runs.
The workflow’s goal is not functional output — it’s purely diagnostic.
By running and resubmitting it from the Azure Portal, you can observe how Azure automatically sets tracking properties like clientTrackingId and sourceHistoryName across multiple executions.
💡 Tip: This design is ideal for learning and troubleshooting. You can safely resubmit, experiment with “Resubmit All” vs “Resubmit from Point of Failure,” and compare how the Logic App records each execution in its run history.
🔍 Behaviour When Running the Demo
💡 Note: The values below come from the Logic App runtime context (
trigger()) which is assigned to arunInfovariable inside the Logic App, not from Application Insights traces. …
1. First (Original) Run
-
isResubmission→false(if sourceHistoryName is empty) -
clientTrackingId→ matches its ownrunId -
sourceHistoryName→ empty
This confirms a fresh trigger invocation — no resubmission.
2. Resubmitted Run
When you click Resubmit in the Azure Portal:
- A new run ID is created.
- The trigger input is replayed with the same payload.
- Azure automatically sets:
-
clientTrackingId = -
sourceHistoryName = -
isResubmission = true(ifsourceHistoryNameis not empty)
-
Both identifiers now point to the first/original failed run, forming a direct link rather than a sequential chain.
3. Multiple Resubmissions
If you resubmit several times from the same failed run or subsequent failed run:
- Each new run still sets
clientTrackingId = sourceHistoryName = - All resubmissions share the same clientTrackingId, effectively grouping them into a resubmission family.
You can correlate related runs easily by checking:
clientTrackingId == originRunId
4. Extended Real-World Scenario (Two Resubmission Families)
Below is a concrete timeline showing two separate resubmission families. The key point: each family has its own origin (the first/original run in that family), and all resubmits in that family will set clientTrackingId and sourceHistoryName to that family origin runId.
Family A — Origin is Run 1
- Run 1 — Original run → Failed
- Run 2 — Resubmitted from the failed step of Run 1 → Failed
- Run 3 — Resubmitted Run 1 again → Succeeded
What you’ll see:
-
clientTrackingId=sourceHistoryName= Run 1 for Run 2 and Run 3 - All telemetry/correlation for this family groups by Run 1 as the origin
Family B — A new original run starts the second family
- Run 4 — New original run → Failed
- Run 5 — Resubmitted Run 4 → Failed
- Run 6 — Resubmitted Run 5 → Failed
- Run 7 — Resubmitted the new failed run in this family (e.g., Run 5 earlier) → Succeeded
What you’ll see:
-
clientTrackingId=sourceHistoryName= Run 4 for Run 5, Run 6, and Run 7 - Even if you resubmit a resubmission (e.g., resubmit Run 5), Azure still tracks it back to the family origin (Run 4) — not to Run 5
Summary Table
| Run | Started As | Tracks To | Status |
|---|---|---|---|
| 1 | Original | 1 | ❌ Failed |
| 2 | Resubmit from Run 1 (failed step) | 1 | ❌ Failed |
| 3 | Resubmit Run 1 again | 1 | ✅ Succeeded |
| 4 | New Original | 4 | ❌ Failed |
| 5 | Resubmit Run 4 | 4 | ❌ Failed |
| 6 | Resubmit Run 5 | 4 | ❌ Failed |
| 7 | Resubmit new failed run (Run 5) | 4 | ✅ Succeeded |
Key insight: Resubmissions always point to the origin run of their own family. If you start a new original run, you start a new family with a different origin.
🧭 Visual Summary
┌───────────────────────────────┐
│ Original Run (Failed) │
│ runId: 0858...25690CU00 │
│ clientTrackingId: same │
└──────────────┬────────────────┘
│
┌───────────────────────┼───────────────────────────┐
│ │ │
▼ ▼ ▼
Resubmit #1 Resubmit #2 Resubmit #3
runId: ...6759CU00 runId: ...7831CU00 runId: ...8595CU00
clientTrackingId = sourceHistoryName = 0858...25690CU00
All resubmissions point directly to the original run — forming a hub-and-spoke structure.
📈 Application Insights — Tracing Resubmission Families
When logging or emitting telemetry to Application Insights, each Logic App run can be correlated using the clientTrackingId.
Because Azure assigns the same clientTrackingId and sourceHistoryName to all resubmitted runs, this field becomes the single link that ties a family of runs together.
Below is a sample Kusto Query Language (KQL) query that retrieves and visualizes resubmissions grouped by clientTrackingId:
traces | extend cd = todynamic(customDimensions)
| where tostring(cd.EventName) == "WorkflowRunEnd" // only completed runs
| extend props = parse_json(tostring(cd["prop__properties"]))
| where isnotempty(props.resource.runId)
| extend
LogicAppName = tostring(coalesce(cd.prop__siteName, props.resource.workflowName)),
workflow = tostring(props.resource.workflowName),
runId = tostring(props.resource.runId),
originRunId = tostring(props.resource.originRunId),
status = tostring(props.status),
clientTrackingId = trim(" ", tostring(coalesce(cd.prop__clientTrackingId, props.resource.originRunId, props.resource.runId))),
sourceHistoryName = tostring(cd.prop__sourceHistoryName)
| extend isResubmitted = clientTrackingId != runId or isnotempty(sourceHistoryName)
| project timestamp, LogicAppName, workflow, runId, originRunId, status, clientTrackingId, sourceHistoryName, isResubmitted
| order by timestamp desc
Example output interpretation:
- All runs that share the same
clientTrackingIdbelong to one resubmission family. - The first run in that family will have an empty
sourceHistoryNameandisResubmission = false. - Each resubmitted run reuses the same
clientTrackingIdandsourceHistoryName= original run ID. - You can group or chart by
clientTrackingIdto view the entire lineage of a workflow’s retry lifecycle.
💡 Tip: Add
| summarize count() by clientTrackingIdto get a quick count of how many resubmissions occurred per family.
🧠 Key Takeaways
- ✅ clientTrackingId and sourceHistoryName (SHN) both reference the original run in a resubmission family.
- ✅ originHistoryName (OHN) changes with each execution and represents the current run’s unique identifier.
- ✅ Resubmit All replays the entire workflow from the trigger, while Resubmit from Point of Failure resumes from the failed step — earlier actions are Skipped, and variables may be stale or unset.
- ✅ For reliable correlation, always use
trigger()properties directly (e.g., SHN, OHN, runId) rather than relying on variables. - ✅ Group by clientTrackingId to view the complete lineage of a workflow’s resubmission family.
- ✅ A new original run starts a fresh family, giving it a distinct
clientTrackingIdandsourceHistoryName.
By applying these practices, you’ll have clear visibility into how Logic Apps handle resubmissions, ensuring consistent tracking, correlation, and auditability across all runs.



