<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic One Cluster per Task — Proven, Ready, and Waiting in Community Articles</title>
    <link>https://community.databricks.com/t5/community-articles/one-cluster-per-task-proven-ready-and-waiting/m-p/150592#M1067</link>
    <description>&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;P class=""&gt;&lt;EM&gt;Part 3 of 3: Databricks Streaming Architecture&lt;/EM&gt;&lt;/P&gt;&lt;P class=""&gt;By the end of&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A class="" href="https://medium.com/@kirankbs/streaming-failure-models-why-it-didnt-crash-is-the-worst-outcome-4e6ee26e444a" rel="noopener" target="_blank"&gt;Part 1&lt;/A&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&amp;amp;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A class="" href="https://medium.com/@kirankbs/multi-task-on-a-shared-cluster-why-thats-also-not-enough-f243be9c847f" rel="noopener" target="_blank"&gt;Part 2&lt;/A&gt;, we knew what the real answer was. We just hadn’t committed to it yet.&lt;/P&gt;&lt;P class=""&gt;Not because it wouldn’t work. We tested it. We documented it. The code was ready. The answer was one cluster per task — true driver isolation, one JVM per pipeline, failures that cannot by construction spread sideways.&lt;/P&gt;&lt;P class=""&gt;The reason we hadn’t switched: budget and scale. That’s a completely legitimate engineering decision.&lt;/P&gt;&lt;H2 id="1588"&gt;What “real” isolation actually means&lt;/H2&gt;&lt;P class=""&gt;Everything in Parts 1 and 2 lived in this shape:&lt;BR /&gt;Shared Job Cluster:&lt;/P&gt;&lt;P class=""&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;SPAN class=""&gt;  Python Proc A    Python Proc B&lt;BR /&gt;       \               /&lt;BR /&gt;        ┌─────────────┐&lt;BR /&gt;        │  Spark JVM  │&lt;BR /&gt;        │  (shared)   │&lt;BR /&gt;        └─────────────┘&lt;BR /&gt;               │&lt;BR /&gt;          Executors&lt;/SPAN&gt;&lt;/PRE&gt;&lt;P class=""&gt;One driver. Everything that fails, fails together — or worse, fails silently while the rest keeps running.&lt;/P&gt;&lt;P class=""&gt;One cluster per task looks like this:&lt;BR /&gt;Dedicated Clusters:&lt;/P&gt;&lt;PRE&gt;&lt;SPAN class=""&gt;  Task A              Task B&lt;BR /&gt;  Cluster A           Cluster B&lt;/SPAN&gt;&lt;SPAN class=""&gt;  &lt;BR /&gt;  Python Proc         Python Proc&lt;BR /&gt;       │                   │&lt;BR /&gt;  ┌─────────┐         ┌─────────┐&lt;BR /&gt;  │  JVM A  │         │  JVM B  │&lt;BR /&gt;  └─────────┘         └─────────┘&lt;BR /&gt;       │                   │&lt;BR /&gt;  Executors           Executors&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;SPAN class=""&gt;Task B fails → Cluster B restarts → Task A: unaffected&lt;/SPAN&gt;&lt;/PRE&gt;&lt;P class=""&gt;That last line is the one that matters. Task B crashing cannot reach Task A. No shared driver, no shared memory, no shared scheduler. The failure boundary is the cluster, not the job.&lt;/P&gt;&lt;H2 id="5e0a"&gt;What the experiment showed&lt;/H2&gt;&lt;P class=""&gt;We ran it. Moved our streaming queries onto separate clusters — some as separate tasks in the same job, some as fully independent jobs. Both approaches worked.&lt;/P&gt;&lt;P class=""&gt;Failures stopped spreading. When we deliberately triggered one, the other pipeline kept running correctly — not “mostly healthy.” The UI was accurate for the first time, which sounds like a minor thing until you remember how long we’d been staring at misleading dashboards.&lt;/P&gt;&lt;P class=""&gt;Debugging got faster in a way that surprised me. Each cluster has its own driver logs, its own metrics, its own lifecycle. “Which pipeline failed?” stopped requiring timestamp correlation across a shared log stream.&lt;/P&gt;&lt;P class=""&gt;Sizing became honest too. A heavy pipeline gets the compute it needs. A lightweight one runs on something smaller. You’re not picking a number that has to cover the worst case across everything.&lt;/P&gt;&lt;H2 id="cc3e"&gt;The code was already ready&lt;/H2&gt;&lt;P class=""&gt;Something we hadn’t fully appreciated: we didn’t need to rewrite anything.&lt;/P&gt;&lt;P class=""&gt;Our pipelines were structured so the same code could run in any deployment shape:&lt;/P&gt;&lt;UL class=""&gt;&lt;LI&gt;All queries in one task, one cluster — the Part 1 setup&lt;/LI&gt;&lt;LI&gt;Multiple tasks, shared cluster — the Part 2 setup&lt;/LI&gt;&lt;LI&gt;Multiple tasks, dedicated cluster per task — the target architecture&lt;/LI&gt;&lt;/UL&gt;&lt;P class=""&gt;Deployment and configuration change, not a code change. The streaming logic, the Delta writes, the checkpointing — all identical. Only the compute allocation changed.&lt;/P&gt;&lt;P class=""&gt;That was intentional. It also made the experiment cheap to run, which helped.&lt;/P&gt;&lt;H2 id="fe83"&gt;Why we’re waiting&lt;/H2&gt;&lt;P class=""&gt;Cost and scale, honestly.&lt;/P&gt;&lt;P class=""&gt;Right now, our workload fits on a shared cluster without catastrophic failure — especially with&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;awaitAnyTermination&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;providing fail-fast semantics on the streaming side and task retries on the batch side. It's not elegant. But it's stable enough for where we are.&lt;/P&gt;&lt;P class=""&gt;Once device count crosses the threshold, the calculus changes. When the operational cost of a missed or false alert exceeds the infrastructure cost of a dedicated cluster, you stop debating. We know roughly where that line is. We’re watching the numbers.&lt;/P&gt;&lt;H2 id="9418"&gt;When to make the move&lt;/H2&gt;&lt;P class=""&gt;If any of these apply to your setup, you’re probably ready:&lt;/P&gt;&lt;UL class=""&gt;&lt;LI&gt;A failure in one pipeline has caused a correctness problem in another&lt;/LI&gt;&lt;LI&gt;You’re spending more time debugging shared-cluster incidents than the extra cluster would cost per month&lt;/LI&gt;&lt;LI&gt;Customer impact from partial failures is measurable — missed alerts, false positives, SLA breaches&lt;/LI&gt;&lt;LI&gt;Individual pipelines have meaningfully different compute profiles and you’re sizing the shared cluster to the worst case&lt;/LI&gt;&lt;/UL&gt;&lt;P class=""&gt;None of these require a crisis. The best time to make the architecture change is before the next incident, not after.&lt;/P&gt;&lt;H2 id="f4d5"&gt;The progression in one diagram&lt;/H2&gt;&lt;PRE&gt;&lt;SPAN class=""&gt;Part 1: Multi-query, shared cluster&lt;BR /&gt;→ Problem: silent query failures&lt;BR /&gt;→ Fix: awaitAnyTermination (band-aid)&lt;BR /&gt;&lt;BR /&gt;Part 2: Multi-task, shared cluster&lt;BR /&gt;→ Problem: still one driver, same failure modes&lt;BR /&gt;→ Fix: task-level retry (better, still shared)&lt;BR /&gt;&lt;BR /&gt;Part 3: One cluster per task&lt;BR /&gt;→ True isolation&lt;BR /&gt;→ Failures contained by construction&lt;BR /&gt;→ Ready when the scale justifies it&lt;/SPAN&gt;&lt;/PRE&gt;&lt;P class=""&gt;The band-aids in Parts 1 and 2 weren’t mistakes. We took a known shortcut because the right answer cost more than the problem did at the time. Knowing that, and knowing what would change it — that’s what matters. We know both.&lt;/P&gt;&lt;P class=""&gt;The code is sitting there, ready to go. We flip the switch when the numbers say it’s time.&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;P class=""&gt;&lt;EM&gt;The incident that kicked off this series also involved a&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;ConcurrentAppendException&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;that went deeper than a simple retry could fix — Delta isolation levels,&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;isBlindAppend&lt;EM&gt;, and why you can't always do what you think you can inside&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;foreachBatch&lt;EM&gt;. That's the next post, and probably the most technically dense thing I'll write this year.&lt;/EM&gt;&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;&lt;SPAN&gt;Full post with architecture diagrams and the series progression summary&lt;/SPAN&gt;: &lt;A href="https://medium.com/@kirankbs/one-cluster-per-task-proven-ready-and-waiting-2da1cc1d77e4" rel="noopener" target="_blank"&gt;Medium&lt;/A&gt; or &lt;A href="https://newsletter.kirankbs.com/p/one-cluster-per-task-proven-ready" rel="noopener" target="_blank"&gt;Substack&lt;/A&gt;&lt;BR /&gt;&lt;BR /&gt;Entire Series:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Part 1: &lt;A href="https://community.databricks.com/t5/community-articles/streaming-failure-models-why-quot-it-didn-t-crash-quot-is-the/td-p/149640" rel="noopener" target="_blank"&gt;&lt;SPAN&gt;Streaming Failure Models: Why "It Didn't Crash" Is the Worst Outcome&lt;/SPAN&gt;&lt;/A&gt;&lt;/LI&gt;&lt;LI&gt;Part 2:&amp;nbsp;&lt;A href="https://community.databricks.com/t5/community-articles/multi-task-on-a-shared-cluster-why-that-s-also-not-enough/td-p/149937" rel="noopener" target="_blank"&gt;&lt;SPAN&gt;Multi-Task on a Shared Cluster — Why That's Also Not Enough&lt;/SPAN&gt;&lt;/A&gt;&lt;/LI&gt;&lt;LI&gt;Part 3: Current One:&amp;nbsp;One Cluster per Task — Proven, Ready, and Waiting&lt;/LI&gt;&lt;/UL&gt;</description>
    <pubDate>Wed, 11 Mar 2026 13:45:44 GMT</pubDate>
    <dc:creator>Kirankumarbs</dc:creator>
    <dc:date>2026-03-11T13:45:44Z</dc:date>
    <item>
      <title>One Cluster per Task — Proven, Ready, and Waiting</title>
      <link>https://community.databricks.com/t5/community-articles/one-cluster-per-task-proven-ready-and-waiting/m-p/150592#M1067</link>
      <description>&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;P class=""&gt;&lt;EM&gt;Part 3 of 3: Databricks Streaming Architecture&lt;/EM&gt;&lt;/P&gt;&lt;P class=""&gt;By the end of&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A class="" href="https://medium.com/@kirankbs/streaming-failure-models-why-it-didnt-crash-is-the-worst-outcome-4e6ee26e444a" rel="noopener" target="_blank"&gt;Part 1&lt;/A&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&amp;amp;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;A class="" href="https://medium.com/@kirankbs/multi-task-on-a-shared-cluster-why-thats-also-not-enough-f243be9c847f" rel="noopener" target="_blank"&gt;Part 2&lt;/A&gt;, we knew what the real answer was. We just hadn’t committed to it yet.&lt;/P&gt;&lt;P class=""&gt;Not because it wouldn’t work. We tested it. We documented it. The code was ready. The answer was one cluster per task — true driver isolation, one JVM per pipeline, failures that cannot by construction spread sideways.&lt;/P&gt;&lt;P class=""&gt;The reason we hadn’t switched: budget and scale. That’s a completely legitimate engineering decision.&lt;/P&gt;&lt;H2 id="1588"&gt;What “real” isolation actually means&lt;/H2&gt;&lt;P class=""&gt;Everything in Parts 1 and 2 lived in this shape:&lt;BR /&gt;Shared Job Cluster:&lt;/P&gt;&lt;P class=""&gt;&amp;nbsp;&lt;/P&gt;&lt;PRE&gt;&lt;SPAN class=""&gt;  Python Proc A    Python Proc B&lt;BR /&gt;       \               /&lt;BR /&gt;        ┌─────────────┐&lt;BR /&gt;        │  Spark JVM  │&lt;BR /&gt;        │  (shared)   │&lt;BR /&gt;        └─────────────┘&lt;BR /&gt;               │&lt;BR /&gt;          Executors&lt;/SPAN&gt;&lt;/PRE&gt;&lt;P class=""&gt;One driver. Everything that fails, fails together — or worse, fails silently while the rest keeps running.&lt;/P&gt;&lt;P class=""&gt;One cluster per task looks like this:&lt;BR /&gt;Dedicated Clusters:&lt;/P&gt;&lt;PRE&gt;&lt;SPAN class=""&gt;  Task A              Task B&lt;BR /&gt;  Cluster A           Cluster B&lt;/SPAN&gt;&lt;SPAN class=""&gt;  &lt;BR /&gt;  Python Proc         Python Proc&lt;BR /&gt;       │                   │&lt;BR /&gt;  ┌─────────┐         ┌─────────┐&lt;BR /&gt;  │  JVM A  │         │  JVM B  │&lt;BR /&gt;  └─────────┘         └─────────┘&lt;BR /&gt;       │                   │&lt;BR /&gt;  Executors           Executors&lt;BR /&gt;&lt;BR /&gt;&lt;/SPAN&gt;&lt;SPAN class=""&gt;Task B fails → Cluster B restarts → Task A: unaffected&lt;/SPAN&gt;&lt;/PRE&gt;&lt;P class=""&gt;That last line is the one that matters. Task B crashing cannot reach Task A. No shared driver, no shared memory, no shared scheduler. The failure boundary is the cluster, not the job.&lt;/P&gt;&lt;H2 id="5e0a"&gt;What the experiment showed&lt;/H2&gt;&lt;P class=""&gt;We ran it. Moved our streaming queries onto separate clusters — some as separate tasks in the same job, some as fully independent jobs. Both approaches worked.&lt;/P&gt;&lt;P class=""&gt;Failures stopped spreading. When we deliberately triggered one, the other pipeline kept running correctly — not “mostly healthy.” The UI was accurate for the first time, which sounds like a minor thing until you remember how long we’d been staring at misleading dashboards.&lt;/P&gt;&lt;P class=""&gt;Debugging got faster in a way that surprised me. Each cluster has its own driver logs, its own metrics, its own lifecycle. “Which pipeline failed?” stopped requiring timestamp correlation across a shared log stream.&lt;/P&gt;&lt;P class=""&gt;Sizing became honest too. A heavy pipeline gets the compute it needs. A lightweight one runs on something smaller. You’re not picking a number that has to cover the worst case across everything.&lt;/P&gt;&lt;H2 id="cc3e"&gt;The code was already ready&lt;/H2&gt;&lt;P class=""&gt;Something we hadn’t fully appreciated: we didn’t need to rewrite anything.&lt;/P&gt;&lt;P class=""&gt;Our pipelines were structured so the same code could run in any deployment shape:&lt;/P&gt;&lt;UL class=""&gt;&lt;LI&gt;All queries in one task, one cluster — the Part 1 setup&lt;/LI&gt;&lt;LI&gt;Multiple tasks, shared cluster — the Part 2 setup&lt;/LI&gt;&lt;LI&gt;Multiple tasks, dedicated cluster per task — the target architecture&lt;/LI&gt;&lt;/UL&gt;&lt;P class=""&gt;Deployment and configuration change, not a code change. The streaming logic, the Delta writes, the checkpointing — all identical. Only the compute allocation changed.&lt;/P&gt;&lt;P class=""&gt;That was intentional. It also made the experiment cheap to run, which helped.&lt;/P&gt;&lt;H2 id="fe83"&gt;Why we’re waiting&lt;/H2&gt;&lt;P class=""&gt;Cost and scale, honestly.&lt;/P&gt;&lt;P class=""&gt;Right now, our workload fits on a shared cluster without catastrophic failure — especially with&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;awaitAnyTermination&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;providing fail-fast semantics on the streaming side and task retries on the batch side. It's not elegant. But it's stable enough for where we are.&lt;/P&gt;&lt;P class=""&gt;Once device count crosses the threshold, the calculus changes. When the operational cost of a missed or false alert exceeds the infrastructure cost of a dedicated cluster, you stop debating. We know roughly where that line is. We’re watching the numbers.&lt;/P&gt;&lt;H2 id="9418"&gt;When to make the move&lt;/H2&gt;&lt;P class=""&gt;If any of these apply to your setup, you’re probably ready:&lt;/P&gt;&lt;UL class=""&gt;&lt;LI&gt;A failure in one pipeline has caused a correctness problem in another&lt;/LI&gt;&lt;LI&gt;You’re spending more time debugging shared-cluster incidents than the extra cluster would cost per month&lt;/LI&gt;&lt;LI&gt;Customer impact from partial failures is measurable — missed alerts, false positives, SLA breaches&lt;/LI&gt;&lt;LI&gt;Individual pipelines have meaningfully different compute profiles and you’re sizing the shared cluster to the worst case&lt;/LI&gt;&lt;/UL&gt;&lt;P class=""&gt;None of these require a crisis. The best time to make the architecture change is before the next incident, not after.&lt;/P&gt;&lt;H2 id="f4d5"&gt;The progression in one diagram&lt;/H2&gt;&lt;PRE&gt;&lt;SPAN class=""&gt;Part 1: Multi-query, shared cluster&lt;BR /&gt;→ Problem: silent query failures&lt;BR /&gt;→ Fix: awaitAnyTermination (band-aid)&lt;BR /&gt;&lt;BR /&gt;Part 2: Multi-task, shared cluster&lt;BR /&gt;→ Problem: still one driver, same failure modes&lt;BR /&gt;→ Fix: task-level retry (better, still shared)&lt;BR /&gt;&lt;BR /&gt;Part 3: One cluster per task&lt;BR /&gt;→ True isolation&lt;BR /&gt;→ Failures contained by construction&lt;BR /&gt;→ Ready when the scale justifies it&lt;/SPAN&gt;&lt;/PRE&gt;&lt;P class=""&gt;The band-aids in Parts 1 and 2 weren’t mistakes. We took a known shortcut because the right answer cost more than the problem did at the time. Knowing that, and knowing what would change it — that’s what matters. We know both.&lt;/P&gt;&lt;P class=""&gt;The code is sitting there, ready to go. We flip the switch when the numbers say it’s time.&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;DIV class=""&gt;&lt;P class=""&gt;&lt;EM&gt;The incident that kicked off this series also involved a&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;ConcurrentAppendException&lt;EM&gt;&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;that went deeper than a simple retry could fix — Delta isolation levels,&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;isBlindAppend&lt;EM&gt;, and why you can't always do what you think you can inside&lt;SPAN&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;/EM&gt;foreachBatch&lt;EM&gt;. That's the next post, and probably the most technically dense thing I'll write this year.&lt;/EM&gt;&lt;/P&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;P&gt;&lt;SPAN&gt;Full post with architecture diagrams and the series progression summary&lt;/SPAN&gt;: &lt;A href="https://medium.com/@kirankbs/one-cluster-per-task-proven-ready-and-waiting-2da1cc1d77e4" rel="noopener" target="_blank"&gt;Medium&lt;/A&gt; or &lt;A href="https://newsletter.kirankbs.com/p/one-cluster-per-task-proven-ready" rel="noopener" target="_blank"&gt;Substack&lt;/A&gt;&lt;BR /&gt;&lt;BR /&gt;Entire Series:&lt;/P&gt;&lt;UL&gt;&lt;LI&gt;Part 1: &lt;A href="https://community.databricks.com/t5/community-articles/streaming-failure-models-why-quot-it-didn-t-crash-quot-is-the/td-p/149640" rel="noopener" target="_blank"&gt;&lt;SPAN&gt;Streaming Failure Models: Why "It Didn't Crash" Is the Worst Outcome&lt;/SPAN&gt;&lt;/A&gt;&lt;/LI&gt;&lt;LI&gt;Part 2:&amp;nbsp;&lt;A href="https://community.databricks.com/t5/community-articles/multi-task-on-a-shared-cluster-why-that-s-also-not-enough/td-p/149937" rel="noopener" target="_blank"&gt;&lt;SPAN&gt;Multi-Task on a Shared Cluster — Why That's Also Not Enough&lt;/SPAN&gt;&lt;/A&gt;&lt;/LI&gt;&lt;LI&gt;Part 3: Current One:&amp;nbsp;One Cluster per Task — Proven, Ready, and Waiting&lt;/LI&gt;&lt;/UL&gt;</description>
      <pubDate>Wed, 11 Mar 2026 13:45:44 GMT</pubDate>
      <guid>https://community.databricks.com/t5/community-articles/one-cluster-per-task-proven-ready-and-waiting/m-p/150592#M1067</guid>
      <dc:creator>Kirankumarbs</dc:creator>
      <dc:date>2026-03-11T13:45:44Z</dc:date>
    </item>
  </channel>
</rss>

