<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Polysync</title>
    <description>The latest articles on DEV Community by Polysync (polysync).</description>
    <link>https://dev.to/polysync</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F15336%2F40a60401-c416-4538-9961-fced9048818d.png</url>
      <title>DEV Community: Polysync</title>
      <link>https://dev.to/polysync</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/polysync"/>
    <language>en</language>
    <item>
      <title>When native cloud schedulers are enough, and when not</title>
      <dc:creator>Samir Elmallah</dc:creator>
      <pubDate>Fri, 16 Oct 2026 10:40:31 +0000</pubDate>
      <link>https://dev.to/polysync/when-native-cloud-schedulers-are-enough-and-when-not-28ll</link>
      <guid>https://dev.to/polysync/when-native-cloud-schedulers-are-enough-and-when-not-28ll</guid>
      <description>&lt;p&gt;Every cloud platform ships with a scheduler. For work that stays inside that platform it is usually the right tool, and adding an orchestrator on top buys you a hop, a credential and a failure mode.&lt;/p&gt;

&lt;p&gt;The trouble starts at the boundary, where one platform's scheduler has to wait on another platform's work and no single graph covers the run. Here are five checks for working out which side of that line you are on, and three ways across it if you are on the wrong side.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five checks
&lt;/h2&gt;

&lt;p&gt;You are still comfortably inside one platform when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every step is a &lt;strong&gt;first-class job in the same platform&lt;/strong&gt;, not an HTTP call;&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;single dependency graph&lt;/strong&gt; covers the whole run;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;monitoring shows the whole run&lt;/strong&gt;, not one platform's slice of it;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;retries and idempotency&lt;/strong&gt; are handled inside the platform;&lt;/li&gt;
&lt;li&gt;adding a step does &lt;strong&gt;not mean inventing a new integration pattern&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are past the edge when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;steps are chained with &lt;strong&gt;storage events, webhooks or polling timers&lt;/strong&gt;;&lt;/li&gt;
&lt;li&gt;a step is a &lt;strong&gt;service call&lt;/strong&gt; rather than a job the scheduler understands;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"did the other platform's job finish?"&lt;/em&gt; is answered by a person, or by a table someone maintains;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lineage and run history stop&lt;/strong&gt; at the platform boundary;&lt;/li&gt;
&lt;li&gt;adding the next platform means building &lt;strong&gt;another bespoke bridge&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All five hold and the native scheduler is enough. Any one fails and you are about to start building glue. That is worth saying plainly: a scheduler that ships with the platform is not a compromise. There is nothing extra to run, retries happen where the failures happen, and the platform's own team keeps it working.&lt;/p&gt;

&lt;h2&gt;
  
  
  What glue actually looks like
&lt;/h2&gt;

&lt;p&gt;Glue is not a product. It is the work that exists because one platform has to wait on another: a storage event that fires a function, a webhook that calls the next platform's API, a polling timer that asks whether the other job finished, or a lookup table somebody keeps current by hand.&lt;/p&gt;

&lt;p&gt;Two properties matter before you build more of it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Glue has no graph.&lt;/strong&gt; The dependency lives in the event subscription or the timer, not in something anyone can draw.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Glue makes the run invisible at the edges.&lt;/strong&gt; Each platform sees only its own slice, so retries, lineage and error handling end at the boundary, and it breaks quietly.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scenario 1: one platform does the whole job
&lt;/h2&gt;

&lt;p&gt;Picture a pipeline where every stage lives in Databricks. Data is ingested from cloud storage and message buses by the platform's declarative pipelines, transformations run in the same pipelines, and unstructured documents are parsed with an AI function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;ai_parse_document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parsed output is indexed for search with Databricks AI Search, and analysts read the result in AI/BI dashboards. Lakeflow Jobs schedules the lot with one dependency graph, and the platform's monitoring shows every task in one place.&lt;/p&gt;

&lt;p&gt;Run the five checks: all five hold. In this shape an external orchestrator removes nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scenario 2: the same pipeline, two platforms
&lt;/h2&gt;

&lt;p&gt;Now mirror it. Ingestion in Azure Data Factory, document extraction on Azure Document Intelligence, transformation on Databricks, the search index in Azure AI Search, dashboards in Power BI.&lt;/p&gt;

&lt;p&gt;Logically identical. Physically it crosses three or four boundaries. Data Factory can invoke a Databricks job directly and has a connector that writes to an Azure AI Search index, so those hops are expressible inside the platform. Document extraction has no first-class activity, so it becomes a Web call, a place where the dependency no longer resolves on its own. The Databricks job schedules its own tasks on its own clock, and Power BI refreshes on a third.&lt;/p&gt;

&lt;p&gt;Run the five checks again. The graph no longer covers the run. Monitoring is split across four consoles. None of this is a defect in any one product. It is what a boundary does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three ways across, and when each is right
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Event glue.&lt;/strong&gt; Storage events, webhooks or a polling timer pick up where the last platform left off. Cheapest to start, and the cost shows up later as silent gaps and manual reconciliation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A scheduler of schedulers.&lt;/strong&gt; One job whose only task is to start other schedulers and wait. It works, but each platform still sees only its own slice, and the outer graph is a script one person owns.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A control plane that spans the platforms.&lt;/strong&gt; Each platform stays the executor; a separate layer holds the dependency graph across them, maps parameters between tasks and keeps one run history.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A simple test settles it: try to answer, for one run, what ran, in what order, and what waited on what. If the honest answer needs four browser tabs, the boundary is costing more than an orchestrator would.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Polysync fits
&lt;/h2&gt;

&lt;p&gt;Polysync is a control plane rather than a replacement for the platforms you already run. It treats pipelines, jobs and functions across Azure, Databricks, Fabric, AWS and Google Cloud as first-class nodes in one dependency graph, and decides what runs, when, and what waits. It does not move your data and does not change how any platform executes its work.&lt;/p&gt;

&lt;p&gt;The article this is based on is the canonical home for this piece, with the figures: &lt;a href="https://www.polysync.com.au/articles/native-cloud-schedulers?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=articles&amp;amp;utm_content=native-cloud-schedulers" rel="noopener noreferrer"&gt;https://www.polysync.com.au/articles/native-cloud-schedulers?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=articles&amp;amp;utm_content=native-cloud-schedulers&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Microsoft, Azure, Azure AI Search, Azure Data Factory, Azure Document Intelligence, Microsoft Fabric and Power BI are trademarks of the Microsoft group of companies. Other trademarks are the property of their respective owners.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>cloud</category>
      <category>infrastructure</category>
      <category>systemdesign</category>
    </item>
    <item>
      <title>Automating cross-platform data pipelines: a practical walkthrough</title>
      <dc:creator>Samir Elmallah</dc:creator>
      <pubDate>Fri, 16 Oct 2026 10:39:33 +0000</pubDate>
      <link>https://dev.to/polysync/automating-cross-platform-data-pipelines-a-practical-walkthrough-3pd1</link>
      <guid>https://dev.to/polysync/automating-cross-platform-data-pipelines-a-practical-walkthrough-3pd1</guid>
      <description>&lt;p&gt;Most teams do not have a transformation problem. Data Factory, Databricks, Functions, Logic Apps, Synapse, Fabric and Cloud Composer all do their respective jobs well. The pain shows up between them: the pipeline that finishes in the morning, the job that should follow it but instead runs on a fixed schedule and hopes the other one is done, the Cloud Function that nobody is sure ran at all.&lt;/p&gt;

&lt;p&gt;Automating a cross-platform pipeline comes down to one question: what is ready to run now? Seven things have to be in place to answer it reliably, and this walkthrough sets them out in the order you would build them. The pattern is not tied to one orchestrator; each step ends with how it looks in Polysync, so the walkthrough doubles as a tour of the product.&lt;/p&gt;

&lt;p&gt;One example runs throughout: a nightly customer refresh. An Azure Data Factory pipeline copies new customer records into Azure storage. A Databricks notebook builds a gold table from them. A Google Cloud Function enriches the new rows. A Power BI dataset publishes the result. Four services across three clouds, and before any of this is automated, three of them run on separate clocks and hope the others have finished.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1. Connect each platform
&lt;/h2&gt;

&lt;p&gt;Before anything can run, the orchestrator has to be able to call each platform for you. Two choices are involved, and they are easy to confuse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does the orchestrator authenticate?&lt;/strong&gt; Every connection picks an authentication method. For the Azure services, one option is the &lt;strong&gt;Polysync Service Principal&lt;/strong&gt;: a multi-tenant application that Polysync owns, which you grant a role to in your own tenant. There is no long-lived secret for you to hold or rotate. The other choices are your own service principal (with a secret or a certificate) and, on the other clouds, the platform's own methods such as an AWS access key or assume-role, or a Google service account key, application default credentials, workload identity federation or an impersonated service account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where does a supplied credential live?&lt;/strong&gt; If you use your own credential, it is stored in a secret vault and referenced by name, rather than pasted into a configuration screen. Polysync reads from Azure Key Vault, AWS Secrets Manager, Google Cloud Secret Manager and HashiCorp Vault, and can also hold the credential in its own managed vault if you would rather not link one of yours. The value is read when a task is dispatched, not copied into the task's configuration.&lt;/p&gt;

&lt;p&gt;Polysync connects to more than 20 services across Azure, AWS and Google Cloud, including Azure Data Factory, Microsoft Fabric, Synapse Pipelines, Databricks and Power BI, AWS Glue and Step Functions, and Google Cloud Composer, Dataflow and Vertex AI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2. Discover jobs instead of redefining them
&lt;/h2&gt;

&lt;p&gt;Once a platform is connected, you should not have to retype what already lives there. Polysync reads the platform's own resources and imports them as Jobs: the ADF pipeline, the Databricks notebook, the Cloud Function, the Power BI dataset. The parameters each resource accepts come with it.&lt;/p&gt;

&lt;p&gt;Keep two words apart. A &lt;strong&gt;Job&lt;/strong&gt; is the resource on the platform. A &lt;strong&gt;Task&lt;/strong&gt; is a configured run of that Job: parameters bound, dependencies attached, a schedule or trigger. The same Job can back several Tasks, so one notebook can serve both the nightly refresh and a one-off backfill without being copied.&lt;/p&gt;

&lt;p&gt;In the example, the four platforms are connected and Polysync imports the copy pipeline, the notebook, the Cloud Function and the dataset refresh. Nothing is rewritten; the resources stay where they are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3. Wire the dependencies, not the clock
&lt;/h2&gt;

&lt;p&gt;A pipeline is a set of relationships, not a set of times. "Run the notebook at 06:15 because the copy usually finishes at 06:10" encodes a guess that will be wrong on the one night it matters. Tell the orchestrator the relationship and let it work out the time.&lt;/p&gt;

&lt;p&gt;Each edge in the graph carries a trigger condition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On Success.&lt;/strong&gt; Run only if the upstream task succeeded. This is the chain in the example: copy, then transform, then enrich, then publish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On Failure.&lt;/strong&gt; Run only if the upstream failed, which is where an alert or a compensation step belongs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On Completion.&lt;/strong&gt; Run whatever the outcome, which is where cleanup belongs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On Skipped.&lt;/strong&gt; Run only if the upstream was skipped by an earlier condition, which keeps branch-and-merge graphs correct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Conditions are resolved across the whole graph, not just the immediate parent, so a skip deep in a branch behaves the way you would expect. A cycle is rejected before a run starts: an accidental loop between two tasks is reported as a configuration error, not discovered as a run that never finishes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4. Pass values between tasks
&lt;/h2&gt;

&lt;p&gt;Useful pipelines hand values along. The copy pipeline knows how many rows it moved, and the notebook needs that count as a parameter. The Cloud Function writes a file and returns its path, and the Power BI refresh needs to know which partition changed. Without parameter mapping, that value travels through a shared file or a table that somebody maintains by hand.&lt;/p&gt;

&lt;p&gt;Polysync maps an output of one task into a parameter of another, across platforms: the row count from the ADF pipeline becomes an input to the Databricks notebook, and the notebook's partition name becomes an input to the Cloud Function. The mapping is part of the task configuration, so it is visible and changeable without touching transformation code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5. Put governance on the queue
&lt;/h2&gt;

&lt;p&gt;Every managed service has hard limits: Databricks job concurrency per workspace, Logic Apps action throughput, Cloud Functions concurrent executions. Parallel triggers turn those limits into HTTP 429 responses, dropped runs and unpredictable spend.&lt;/p&gt;

&lt;p&gt;Two different controls put a ceiling on that, and they are worth keeping apart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;concurrency limit&lt;/strong&gt; caps how many tasks are in flight against the platform at once. New work waits until a slot opens.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;rate limit&lt;/strong&gt; caps how many tasks are dispatched in a period of time (per second, minute or hour), using a token bucket, a leaky bucket or a sliding window.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A profile carries one or both, and because it is attached to a platform or a set of platforms you choose the scope: a separate budget per platform, or one budget shared across several. A busy Databricks workspace therefore cannot hold up work aimed at an unrelated Data Factory factory, and several services driving the same downstream database can be held to a single shared ceiling.&lt;/p&gt;

&lt;p&gt;The queue is also where waiting happens: a task whose dependencies are not yet met waits there, rather than polling the platform and piling up activity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6. Schedule the roots
&lt;/h2&gt;

&lt;p&gt;Schedules attach to root tasks, the ones with nothing upstream. They use standard cron with a timezone, and there is a visual builder if you would rather not count asterisks. A task can carry more than one schedule.&lt;/p&gt;

&lt;p&gt;Everything downstream runs because the graph says it is ready, not because it was given its own clock. In the example, only the ADF copy is scheduled. The transform, the enrichment and the publish have no times of their own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7. Watch it in one place
&lt;/h2&gt;

&lt;p&gt;The point of all of the above is to answer "what is happening right now" on one screen. Polysync shows queue depth, the tasks currently dispatched, recent run history, durations and status breakdowns across every connected platform, so a run that spans four services reads as one run instead of four consoles.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you end up with
&lt;/h2&gt;

&lt;p&gt;A pipeline that no longer depends on someone remembering which portal to open first, and a schedule that states a relationship rather than a hope. The graph triggers itself, the queue applies the limits, and one view tells the truth about what ran. The orchestrator becomes the system of record for what your data platform actually did last night.&lt;/p&gt;

&lt;p&gt;The figures that go with each step, and the full walkthrough, are in the original article on our website: &lt;a href="https://www.polysync.com.au/articles/data-pipeline-automation?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=articles&amp;amp;utm_content=data-pipeline-automation" rel="noopener noreferrer"&gt;https://www.polysync.com.au/articles/data-pipeline-automation?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=articles&amp;amp;utm_content=data-pipeline-automation&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Polysync
&lt;/h2&gt;

&lt;p&gt;Polysync Data Solutions is an Australian company that builds cross-platform orchestration for data, integration and AI workloads. It coordinates the platforms you already run rather than replacing them.&lt;/p&gt;

&lt;p&gt;Microsoft, Azure, Azure Data Factory, Azure Databricks, Azure Synapse, Azure Functions, Logic Apps and Microsoft Fabric are trademarks of the Microsoft group of companies. Other product names, logos and brands are the property of their respective owners.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>automation</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>ADF vs Polysync: when Azure Data Factory stops being enough</title>
      <dc:creator>Samir Elmallah</dc:creator>
      <pubDate>Fri, 16 Oct 2026 10:39:20 +0000</pubDate>
      <link>https://dev.to/polysync/adf-vs-polysync-when-azure-data-factory-stops-being-enough-g5f</link>
      <guid>https://dev.to/polysync/adf-vs-polysync-when-azure-data-factory-stops-being-enough-g5f</guid>
      <description>&lt;p&gt;Azure Data Factory is a strong data integration service. Within a single factory you get visual pipelines, a large connector library, parameterised datasets and linked services, schedule and tumbling-window triggers, and an integration runtime that can reach hybrid sources. For a team whose data lives inside Azure, ADF is often the right primary tool, and nothing here argues for replacing it.&lt;/p&gt;

&lt;p&gt;The conversation gets interesting when Data Factory stops being the only thing in the room.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where ADF's orchestration model runs out
&lt;/h2&gt;

&lt;p&gt;ADF's scheduling and dependency primitives are built around the assumption that the work being coordinated is also in ADF. Once that assumption breaks, three gaps appear quickly.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dependencies stop at the factory boundary.&lt;/strong&gt; ADF activity dependencies (&lt;code&gt;dependsOn&lt;/code&gt;) resolve between activities inside the same pipeline. You can invoke one pipeline from another with the Execute Pipeline activity, but a Databricks job kicked off elsewhere, a Cloud Function on Google Cloud, or an external arrival event cannot participate as a first-class node in an ADF dependency graph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Triggers fire from a clock, not from a graph.&lt;/strong&gt; Schedule and tumbling-window triggers know &lt;em&gt;when&lt;/em&gt; to run, but they do not natively express "run this pipeline only after that unrelated workload finishes successfully on another platform". Teams bridge the gap with custom code, a queue, or a third system that polls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency control is per pipeline, not per platform.&lt;/strong&gt; ADF lets you cap a single pipeline's concurrent runs. It does not give you a global budget that says "no more than eight things running against this Databricks workspace, across all sources". When the same cluster is driven by ADF, a notebook job and an ad-hoc workflow, that budget has to live somewhere outside ADF.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Changing a schedule should not be a deployment
&lt;/h2&gt;

&lt;p&gt;In ADF, a trigger is part of the factory's definition. Changing when a pipeline runs means editing the trigger and publishing the factory, the same path a pipeline change takes, and publishing restarts the trigger with the new definition. With Git integration and CI/CD, that is a pull request, a review and a deploy window. A reasonable amount of ceremony for a change to pipeline logic, and a lot for "move this job fifteen minutes earlier".&lt;/p&gt;

&lt;p&gt;When schedules and dependencies are data rather than artifacts, the change is an edit. An operator moves the time in the UI and the scheduler picks up the new definition on its next cycle. No branch, no review, no deploy, and the audit trail is the record of the change itself rather than a commit that has to be released before it counts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring stops at the factory door
&lt;/h2&gt;

&lt;p&gt;ADF Monitor shows ADF runs, which is exactly the right scope when ADF is the only thing running. The moment a run depends on a Databricks job, a Logic App, a Fabric pipeline or a Cloud Function, "did the whole run succeed?" is a question no single console answers. Azure Monitor and Log Analytics can collect the pieces once diagnostic settings are wired for every resource, and each service still keeps its own notion of a run. The result is a status question answered by opening four monitors and comparing timestamps.&lt;/p&gt;

&lt;p&gt;A control plane keeps one run history. Every task, whatever platform executes it, records a status, a duration and its place in the dependency graph, and a retry is traced back to the original attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  You pay for orchestration, including the waiting
&lt;/h2&gt;

&lt;p&gt;ADF bills per activity run, an ordinary way for a consumption service to price coordination. The consequence worth understanding is that an activity which only orchestrates is an activity run like any other. A &lt;code&gt;Lookup&lt;/code&gt;, a &lt;code&gt;Wait&lt;/code&gt;, a &lt;code&gt;Web&lt;/code&gt; call, each pass through an &lt;code&gt;Until&lt;/code&gt; loop: they all count, whether or not a byte of data moves.&lt;/p&gt;

&lt;p&gt;That makes the polling pattern expensive in a specific way. Using ADF to watch for something that happens elsewhere, such as a file landing or another platform's job finishing, means repeated activities that do no data work. The pipeline is billed for waiting. A control plane that waits on the other platforms' own tasks does so at the queue: a dependency resolves when the upstream run reports completion, and no platform activity is created in the meantime.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metadata-driven pipelines and the glue-code bill
&lt;/h2&gt;

&lt;p&gt;ADF can be made metadata-driven, and experienced teams do it: a control table is read by a &lt;code&gt;Lookup&lt;/code&gt;, the rows drive a &lt;code&gt;ForEach&lt;/code&gt;, an &lt;code&gt;If&lt;/code&gt; or &lt;code&gt;Switch&lt;/code&gt; chooses the activity, and the outcome is written back. It is a sound pattern and it is also a framework: a parent pipeline, a table schema, error handling and parameter contracts that someone owns and maintains, and that every organisation builds a slightly different version of.&lt;/p&gt;

&lt;p&gt;The cost is not the first pipeline. It is the second platform, where the framework has to be rebuilt because ADF cannot iterate over a Databricks job or a Cloud Function as a first-class node. Then the third platform, and then the person who leaves.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a control plane adds around ADF
&lt;/h2&gt;

&lt;p&gt;Polysync treats ADF pipelines as first-class nodes in a larger dependency graph. It does not run the transformations; ADF still does that. It decides when ADF runs, what runs alongside it, and what waits for it.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform DAG.&lt;/strong&gt; An ADF pipeline can depend on a Databricks job, which can depend on a Synapse pipeline, which can depend on a Google Cloud Function. Trigger conditions (on success, on failure, on completion, on skipped) are resolved recursively across the whole graph.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-discovery of pipelines.&lt;/strong&gt; Polysync connects to the factory and discovers existing pipelines, exposing them as Jobs you configure into Tasks. No retyping names or parameters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parameter mapping across platforms.&lt;/strong&gt; A row count, a file path or a status produced by an ADF pipeline becomes an input to a downstream task on another platform, without a custom passthrough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Concurrency and rate limits across platforms.&lt;/strong&gt; Concurrency profiles apply two kinds of control: a concurrency limit on how many runs may be in flight, and a rate limit (token bucket, leaky bucket or sliding window) on how many may start per period. A profile can be scoped to a single platform or shared across several, so an ADF run, a Databricks job and a Logic App invocation can all count against the same budget for the same downstream resource.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One monitoring view.&lt;/strong&gt; Every run across every connected platform appears in a single dashboard with status, duration and history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard cron with a visual builder.&lt;/strong&gt; Schedules attach to root tasks in standard cron syntax with timezone awareness, and a task can carry more than one schedule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Changes without a deployment.&lt;/strong&gt; Schedules, dependencies and parameters are configuration, so changing them is an edit rather than a release.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Waiting without activity cost.&lt;/strong&gt; A task waits for its upstream dependencies at the queue; the platform is only called once they are satisfied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No orchestration code to maintain.&lt;/strong&gt; There is no parent pipeline or control-table framework to build, own and hand over.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Side by side
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ADF on its own&lt;/th&gt;
&lt;th&gt;ADF with a cross-platform control plane&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dependencies inside a pipeline, not across platforms&lt;/td&gt;
&lt;td&gt;ADF pipelines as nodes in a cross-platform DAG&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per-pipeline concurrency, no global budget&lt;/td&gt;
&lt;td&gt;Concurrency budgets that span connected platforms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Triggers driven by clock or window, not graph state&lt;/td&gt;
&lt;td&gt;Triggers driven by upstream task state, with trigger conditions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monitoring scoped to the factory&lt;/td&gt;
&lt;td&gt;One dashboard across the platforms in the flow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hand-rolled glue when work spans services&lt;/td&gt;
&lt;td&gt;Parameters mapped between tasks without bespoke code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A schedule change is a release&lt;/td&gt;
&lt;td&gt;Schedules and dependencies change in the UI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orchestration and polling are billable activity runs&lt;/td&gt;
&lt;td&gt;Waiting happens at the queue, not in billable activities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Metadata-driven work needs a framework you maintain&lt;/td&gt;
&lt;td&gt;The graph, parameters and schedules are the configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Will I still need ADF? Yes
&lt;/h2&gt;

&lt;p&gt;Polysync does not move bytes. If you use ADF today to copy from on-premises SQL into ADLS, that activity is still in ADF and still uses your integration runtime. Polysync calls the pipeline, waits for it, captures its result, and decides what runs next.&lt;/p&gt;

&lt;h2&gt;
  
  
  When ADF alone is still the right answer
&lt;/h2&gt;

&lt;p&gt;If every pipeline you operate lives inside one ADF instance, your dependencies are simple, and you have no plans to bring Databricks, Functions, Logic Apps, Synapse, Fabric or Google Cloud services into the same flow, ADF's built-in scheduling is fine. Adding a separate orchestrator before you need one is overhead, not insurance.&lt;/p&gt;

&lt;p&gt;The point at which most teams cross the line is the second platform: the first Databricks job, the first Cloud Function, the first workload that has to coordinate with an ADF pipeline. The full comparison, with the figures, is in the original article on our website: &lt;a href="https://www.polysync.com.au/articles/adf-vs-polysync?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=articles&amp;amp;utm_content=adf-vs-polysync" rel="noopener noreferrer"&gt;https://www.polysync.com.au/articles/adf-vs-polysync?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=articles&amp;amp;utm_content=adf-vs-polysync&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Polysync
&lt;/h2&gt;

&lt;p&gt;Polysync Data Solutions is an Australian company that builds cross-platform orchestration for data, integration and AI workloads. It coordinates the platforms you already run rather than replacing them.&lt;/p&gt;

&lt;p&gt;Microsoft, Azure, Azure Data Factory, Azure Databricks, Azure Synapse, Azure Functions, Logic Apps and Microsoft Fabric are trademarks of the Microsoft group of companies. Other product names, logos and brands are the property of their respective owners.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>azure</category>
      <category>data</category>
    </item>
    <item>
      <title>What is ETL orchestration? A technical guide</title>
      <dc:creator>Samir Elmallah</dc:creator>
      <pubDate>Fri, 16 Oct 2026 10:38:49 +0000</pubDate>
      <link>https://dev.to/polysync/what-is-etl-orchestration-a-technical-guide-46l2</link>
      <guid>https://dev.to/polysync/what-is-etl-orchestration-a-technical-guide-46l2</guid>
      <description>&lt;p&gt;&lt;strong&gt;ETL orchestration&lt;/strong&gt; is the discipline of running data pipelines in the right order, at the right time, under the right resource constraints, with the right response when something fails. It is the layer between your scheduler and the cloud services that actually move and transform data.&lt;/p&gt;

&lt;p&gt;A useful working definition: orchestration is the runtime that turns a graph of work into a sequence of platform API calls, applies governance to those calls, and records what happened.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling is not orchestration
&lt;/h2&gt;

&lt;p&gt;The two terms get used interchangeably. They are not the same thing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scheduling&lt;/strong&gt; answers a single question: &lt;em&gt;when should this start?&lt;/em&gt; A cron expression and a clock are enough.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration&lt;/strong&gt; answers four: &lt;em&gt;when does it start, what has to finish first, how many copies can run at once, and what happens on failure?&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every scheduler is a tiny orchestrator, and every orchestrator contains a scheduler. The interesting design choices live in the other three questions.&lt;/p&gt;

&lt;h2&gt;
  
  
  The DAG is the core data structure
&lt;/h2&gt;

&lt;p&gt;Workflows are modelled as a &lt;strong&gt;directed acyclic graph (DAG)&lt;/strong&gt;. Each node is a task. Each edge declares that one task must wait for another before it runs. The "acyclic" part is non-negotiable: if task A waits for B and B waits for A, neither can ever start. A real orchestrator detects that loop before it executes anything and refuses the run.&lt;/p&gt;

&lt;p&gt;Edges usually carry a &lt;em&gt;trigger condition&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;On Success.&lt;/strong&gt; Run the downstream task only if the upstream task finished successfully.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On Failure.&lt;/strong&gt; Run it only if the upstream failed, which is where alerting or compensation belongs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On Completion.&lt;/strong&gt; Run regardless of outcome, which is where cleanup belongs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On Skipped.&lt;/strong&gt; Run only if the upstream task was skipped by an earlier condition.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A solid orchestrator resolves these conditions &lt;em&gt;recursively&lt;/em&gt;: the status of a node is a function of the resolved status of its ancestors, not just its immediate parent. That is what allows complex branches and skip paths to behave correctly without manual bookkeeping.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dispatchers, queues, and why they run separately
&lt;/h2&gt;

&lt;p&gt;The component that actually calls the cloud platform API is the &lt;strong&gt;dispatcher&lt;/strong&gt;. In any non-trivial orchestrator it runs as a separate process from the scheduler and from the UI, for three reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Throughput.&lt;/strong&gt; Dispatching is bursty. Decoupling lets you scale dispatchers without scaling the UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Isolation.&lt;/strong&gt; A misbehaving platform connection (slow API, throttling, auth failure) should not freeze unrelated work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Durability.&lt;/strong&gt; If the dispatcher restarts, work in the queue is still there, and the scheduler keeps producing work even if a dispatcher is busy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The channel between them is typically a queue table or a message broker, and the queue is where governance lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Concurrency limits and rate limits are different controls
&lt;/h2&gt;

&lt;p&gt;Both protect a downstream service from being overwhelmed, and they are not the same thing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;concurrency limit&lt;/strong&gt; caps how many tasks may be &lt;em&gt;in flight&lt;/em&gt; against a platform at any moment. New work waits until a slot opens.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;rate limit&lt;/strong&gt; caps how many tasks may &lt;em&gt;start&lt;/em&gt; in a period of time (per second, minute or hour). A token bucket starts full and admits a burst before settling to the refill rate, a leaky bucket drains at a fixed rate, and a sliding window counts starts inside a rolling period.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cloud services publish limits that map onto one or both: Databricks job concurrency per workspace, Data Factory pipeline concurrency, Logic Apps action throughput, Cloud Functions concurrent executions. Hitting them shows up as HTTP 429 responses, dropped runs and retry storms.&lt;/p&gt;

&lt;p&gt;A mature orchestrator expresses both, and lets you choose the &lt;strong&gt;scope&lt;/strong&gt;. A separate budget per platform keeps one busy workspace from starving unrelated work; a single shared budget is what you want when different services all drive the same downstream database.&lt;/p&gt;

&lt;h2&gt;
  
  
  State, retries and idempotency
&lt;/h2&gt;

&lt;p&gt;Distributed work fails for boring reasons: network blips, transient throttling, expired tokens, mid-flight deployments. A retry policy is not optional; it is part of the contract.&lt;/p&gt;

&lt;p&gt;The non-obvious part is idempotency. A retry is safe only if the underlying platform call is idempotent, or the orchestrator tracks the original run identifier. Good orchestrators capture the platform-side run ID on first dispatch and reconcile state from it on retry, rather than blindly issuing a second call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Metadata-driven vs code-driven
&lt;/h2&gt;

&lt;p&gt;Two design schools dominate the market.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code-driven&lt;/strong&gt; orchestrators (Airflow, Dagster, Prefect) express workflows as code: the graph is built by evaluating that definition each time a run starts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata-driven&lt;/strong&gt; orchestrators express workflows as configuration: the graph is stored as data and read at run time, so it can change without a code deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are valid. Code-driven gives you arbitrary logic and version-control diffs. Metadata-driven gives you a UI non-engineers can use, hot reload without redeployment, and a cleanly auditable configuration store. The right answer depends on who owns the pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Polysync fits
&lt;/h2&gt;

&lt;p&gt;Polysync is a metadata-driven orchestrator for work that spans platforms. Jobs are discovered from each connected platform rather than retyped, the dependency graph is resolved recursively with cycle detection before a run starts, the dispatcher is a separate process with state and locking that survive restarts, and concurrency and rate limits are applied as profiles you can scope per platform or share across several. Credentials live in a vault you control (Azure Key Vault, AWS Secrets Manager, Google Cloud Secret Manager, HashiCorp Vault), or in Polysync's managed vault if you would rather not link one of yours.&lt;/p&gt;

&lt;p&gt;For the worked examples and the diagrams, read the full article on our website: &lt;a href="https://www.polysync.com.au/articles/what-is-etl-orchestration?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=articles&amp;amp;utm_content=what-is-etl-orchestration" rel="noopener noreferrer"&gt;https://www.polysync.com.au/articles/what-is-etl-orchestration?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=articles&amp;amp;utm_content=what-is-etl-orchestration&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Polysync
&lt;/h2&gt;

&lt;p&gt;Polysync Data Solutions is an Australian company that builds cross-platform orchestration for data, integration and AI workloads. It coordinates the platforms you already run rather than replacing them.&lt;/p&gt;

&lt;p&gt;Microsoft, Azure, Azure Data Factory, Azure Databricks, Logic Apps and Microsoft Marketplace are trademarks of the Microsoft group of companies. Other product names, logos and brands are the property of their respective owners.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>backend</category>
      <category>dataengineering</category>
    </item>
  </channel>
</rss>
