<?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: Chen Debra</title>
    <description>The latest articles on DEV Community by Chen Debra (@chen_debra_3060b21d12b1b0).</description>
    <link>https://dev.to/chen_debra_3060b21d12b1b0</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%2Fuser%2Fprofile_image%2F1533306%2Fc0ea3a94-ba17-47c8-9304-4571fb1adaf9.png</url>
      <title>DEV Community: Chen Debra</title>
      <link>https://dev.to/chen_debra_3060b21d12b1b0</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chen_debra_3060b21d12b1b0"/>
    <language>en</language>
    <item>
      <title>🔥 Skip ZooKeeper! Discover two proven registry alternatives for Apache DolphinScheduler and simplify your architecture. 🚀
#ApacheDolphinScheduler #OpenSource #CloudNative #DevOps</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Thu, 02 Jul 2026 07:32:53 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/skip-zookeeper-discover-two-proven-registry-alternatives-for-apache-dolphinscheduler-and-1e29</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/skip-zookeeper-discover-two-proven-registry-alternatives-for-apache-dolphinscheduler-and-1e29</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/chen_debra_3060b21d12b1b0/running-apache-dolphinscheduler-without-zookeeper-two-proven-registry-alternatives-3n79" class="crayons-story__hidden-navigation-link"&gt;Running Apache DolphinScheduler Without ZooKeeper: Two Proven Registry Alternatives&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/chen_debra_3060b21d12b1b0" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1533306%2Fc0ea3a94-ba17-47c8-9304-4571fb1adaf9.png" alt="chen_debra_3060b21d12b1b0 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/chen_debra_3060b21d12b1b0" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Chen Debra
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Chen Debra
                
              
              &lt;div id="story-author-preview-content-4048311" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/chen_debra_3060b21d12b1b0" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1533306%2Fc0ea3a94-ba17-47c8-9304-4571fb1adaf9.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Chen Debra&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/chen_debra_3060b21d12b1b0/running-apache-dolphinscheduler-without-zookeeper-two-proven-registry-alternatives-3n79" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 2&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/chen_debra_3060b21d12b1b0/running-apache-dolphinscheduler-without-zookeeper-two-proven-registry-alternatives-3n79" id="article-link-4048311"&gt;
          Running Apache DolphinScheduler Without ZooKeeper: Two Proven Registry Alternatives
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/apachedolphinscheduler"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;apachedolphinscheduler&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/zookeeper"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;zookeeper&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/datascience"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;datascience&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/bigdata"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;bigdata&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/chen_debra_3060b21d12b1b0/running-apache-dolphinscheduler-without-zookeeper-two-proven-registry-alternatives-3n79#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Running Apache DolphinScheduler Without ZooKeeper: Two Proven Registry Alternatives</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Thu, 02 Jul 2026 07:32:23 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/running-apache-dolphinscheduler-without-zookeeper-two-proven-registry-alternatives-3n79</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/running-apache-dolphinscheduler-without-zookeeper-two-proven-registry-alternatives-3n79</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxdcv40b4qxo0tjzmixig.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fxdcv40b4qxo0tjzmixig.jpg" width="798" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When designing a distributed scheduling platform, the choice of a service registry has a direct impact on both system architecture and operational complexity. Although Apache DolphinScheduler uses ZooKeeper as its default registry center, it also provides multiple alternatives that allow users to choose the solution that best fits their existing infrastructure and operational capabilities.&lt;/p&gt;

&lt;p&gt;Instead of forcing every deployment to rely on ZooKeeper, DolphinScheduler offers greater flexibility by supporting both &lt;strong&gt;JDBC Registry&lt;/strong&gt; and &lt;strong&gt;Etcd Registry&lt;/strong&gt;, giving organizations more options for different deployment scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Do Some Teams Prefer Not to Use ZooKeeper?
&lt;/h2&gt;

&lt;p&gt;ZooKeeper has long been the de facto coordination service for distributed systems. It is mature, reliable, and battle-tested. However, many teams still hesitate to introduce it into their environments for several practical reasons.&lt;/p&gt;

&lt;h3&gt;
  
  
  Higher Operational Complexity
&lt;/h3&gt;

&lt;p&gt;Running ZooKeeper requires deploying and maintaining an independent cluster. In production environments, at least three nodes are typically recommended to achieve high availability. For smaller teams or organizations with limited infrastructure resources, maintaining an additional distributed system increases both operational overhead and maintenance costs.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Additional Technology Stack
&lt;/h3&gt;

&lt;p&gt;Many organizations already operate around relational databases such as MySQL or PostgreSQL. Introducing ZooKeeper means adopting and maintaining another technology stack, which requires additional expertise and increases the learning curve for operations teams.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extra Infrastructure Costs
&lt;/h3&gt;

&lt;p&gt;ZooKeeper consumes dedicated computing resources, including CPU, memory, storage, and networking. For organizations aiming to simplify infrastructure or reduce resource consumption, these additional requirements may become an unnecessary burden.&lt;/p&gt;

&lt;h2&gt;
  
  
  Registry Alternatives in Apache DolphinScheduler
&lt;/h2&gt;

&lt;p&gt;To address different deployment requirements, Apache DolphinScheduler currently provides two production-ready alternatives to ZooKeeper:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;JDBC Registry&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Etcd Registry&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each solution offers the same core capabilities required by the scheduler while targeting different infrastructure preferences.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 1: JDBC Registry
&lt;/h2&gt;

&lt;p&gt;One of the most innovative features in Apache DolphinScheduler is the &lt;strong&gt;JDBC Registry&lt;/strong&gt;, which eliminates the need for an additional registry service by leveraging an existing relational database such as MySQL or PostgreSQL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo66kjiuauar21uqownjv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo66kjiuauar21uqownjv.png" alt="1" width="799" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;Instead of relying on an external coordination service, the JDBC Registry reproduces the essential capabilities of ZooKeeper using relational database tables.&lt;/p&gt;

&lt;h4&gt;
  
  
  Event Notification
&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;JdbcRegistryDataChangeListenerAdapter&lt;/code&gt; converts database changes—including record creation, updates, and deletions—into DolphinScheduler &lt;code&gt;Event&lt;/code&gt; notifications that trigger registered &lt;code&gt;SubscribeListener&lt;/code&gt; callbacks.&lt;/p&gt;

&lt;p&gt;Internally, the registry detects changes through polling or trigger-based mechanisms, effectively simulating ZooKeeper's Watcher functionality.&lt;/p&gt;

&lt;h4&gt;
  
  
  Distributed Locking
&lt;/h4&gt;

&lt;p&gt;The JDBC Registry provides two methods for acquiring distributed locks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;acquireLock(String key)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;acquireLock(String key, long timeout)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These methods support both blocking and timeout-based lock acquisition.&lt;/p&gt;

&lt;p&gt;Locks are managed through database records to ensure mutual exclusion across distributed nodes. Registry entries are categorized into two types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EPHEMERAL&lt;/strong&gt; — Temporary entries that are automatically cleaned up through heartbeat detection when a client disconnects or fails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PERSISTENT&lt;/strong&gt; — Permanent entries that remain available until explicitly removed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This mechanism enables reliable distributed coordination without requiring ZooKeeper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment Steps
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Step 1: Initialize the Registry Tables
&lt;/h4&gt;

&lt;p&gt;Execute the appropriate initialization script according to your database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MySQL:&lt;/strong&gt; &lt;code&gt;src/main/resources/mysql_registry_init.sql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PostgreSQL:&lt;/strong&gt; &lt;code&gt;src/main/resources/postgresql_registry_init.sql&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 2: Update the Configuration
&lt;/h4&gt;

&lt;p&gt;Add the following configuration to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;master-server/conf/application.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker-server/conf/application.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api-server/conf/application.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc&lt;/span&gt;
  &lt;span class="na"&gt;heartbeat-refresh-interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3s&lt;/span&gt;
  &lt;span class="na"&gt;session-timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;
  &lt;span class="na"&gt;hikari-config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;jdbc-url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:mysql://127.0.0.1:3306/dolphinscheduler&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
    &lt;span class="na"&gt;maximum-pool-size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
    &lt;span class="na"&gt;connection-timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;9000&lt;/span&gt;
    &lt;span class="na"&gt;idle-timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;600000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 3: Add the Database Driver
&lt;/h4&gt;

&lt;p&gt;If you are using MySQL, copy the &lt;code&gt;mysql-connector-java.jar&lt;/code&gt; driver into the DolphinScheduler classpath. The MySQL JDBC driver is intentionally not bundled with the official distribution package, so it must be provided separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;With the JDBC registry, the MasterServer and WorkerServer of Apache DolphinScheduler store metadata in a relational database. Database transactions ensure data consistency, while the heartbeat mechanism enables service discovery and failure detection.&lt;/p&gt;

&lt;p&gt;This approach is particularly suitable for environments that already have a mature database operations team, allowing organizations to take full advantage of their existing database infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Option 2: Etcd Registry
&lt;/h2&gt;

&lt;p&gt;Etcd is a distributed key-value store designed for the cloud-native era and is especially well suited for Kubernetes and other cloud-native environments. The Etcd registry implementation in Apache DolphinScheduler is built on the Jetcd client library and provides functionality similar to ZooKeeper.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fly1xskhgfv1ucwuzfz41.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fly1xskhgfv1ucwuzfz41.png" alt="2" width="799" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Event Listening&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;EtcdRegistry&lt;/code&gt; class uses Etcd's Watch API to monitor changes (create, update, and delete operations) on a specified key or key prefix. It converts the underlying Etcd watch events into DolphinScheduler &lt;code&gt;Event&lt;/code&gt; objects and triggers the &lt;code&gt;SubscribeListener&lt;/code&gt; callback to provide real-time notifications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distributed Locking&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EtcdKeepAliveLeaseManager&lt;/code&gt; grants leases with a specified TTL and continuously keeps them alive using Etcd's keep-alive mechanism. If a client disconnects, the lease expires automatically, releasing the lock without requiring manual intervention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connection Health Monitoring&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;EtcdConnectionStateListener&lt;/code&gt; monitors the connection state between Apache DolphinScheduler and the Etcd cluster. When the connection is lost or restored, it automatically re-establishes distributed locks or re-registers services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Update the Configuration Files
&lt;/h4&gt;

&lt;p&gt;Add the following configuration to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;master-server/conf/application.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;worker-server/conf/application.yaml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;api-server/conf/application.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;registry&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;etcd&lt;/span&gt;
  &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://etcd0:2379,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://etcd1:2379,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://etcd2:2379"&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dolphinscheduler&lt;/span&gt;
  &lt;span class="na"&gt;connection-timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;9s&lt;/span&gt;
  &lt;span class="na"&gt;retry-delay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60ms&lt;/span&gt;
  &lt;span class="na"&gt;retry-max-delay&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;300ms&lt;/span&gt;
  &lt;span class="na"&gt;retry-max-duration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1500ms&lt;/span&gt;
  &lt;span class="c1"&gt;# Optional SSL configuration&lt;/span&gt;
  &lt;span class="na"&gt;cert-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deploy/kubernetes/dolphinscheduler/etcd-certs/ca.crt"&lt;/span&gt;
  &lt;span class="na"&gt;key-cert-chain-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deploy/kubernetes/dolphinscheduler/etcd-certs/client.crt"&lt;/span&gt;
  &lt;span class="na"&gt;key-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deploy/kubernetes/dolphinscheduler/etcd-certs/client.pem"&lt;/span&gt;
  &lt;span class="c1"&gt;# Optional authentication configuration&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="na"&gt;authority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. SSL Configuration Notes
&lt;/h4&gt;

&lt;p&gt;If SSL is enabled on the Etcd server, make sure your JDK version is newer than Java 8u252 (released in April 2020). JDK 11 is also fully supported. The Docker images currently use JDK 8u362, which works correctly.&lt;/p&gt;

&lt;p&gt;This requirement exists because native ALPN support was introduced starting with Java 8u252.&lt;/p&gt;

&lt;h3&gt;
  
  
  Results
&lt;/h3&gt;

&lt;p&gt;With the Etcd registry, Apache DolphinScheduler can fully leverage Etcd's strong consistency and high availability to deliver low latency, excellent scalability, and simplified deployment in cloud-native environments.&lt;/p&gt;

&lt;p&gt;This option is especially suitable for teams that already use Kubernetes and the Etcd technology stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Design?
&lt;/h2&gt;

&lt;p&gt;The design philosophy behind providing multiple registry implementations in Apache DolphinScheduler is straightforward: &lt;strong&gt;reduce dependencies on external components and allow users to choose the registry that best fits their environment.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This philosophy has been consistently reflected throughout the evolution of Apache DolphinScheduler. The project previously implemented a Redis-based queue, but the Redis implementation was eventually removed to reduce external dependencies.&lt;/p&gt;

&lt;p&gt;Today, multiple registry options are provided not to replace ZooKeeper, but to give users greater flexibility when selecting the deployment architecture that best meets their requirements.&lt;/p&gt;

&lt;p&gt;For Kubernetes deployments, this flexibility is reflected in the &lt;code&gt;values.yaml&lt;/code&gt; configuration of the Helm Chart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;zookeeper&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;  &lt;span class="c1"&gt;# Enabled by default&lt;/span&gt;

&lt;span class="na"&gt;registryEtcd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;  &lt;span class="c1"&gt;# Enable manually if needed&lt;/span&gt;

&lt;span class="na"&gt;registryJdbc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;  &lt;span class="c1"&gt;# Enable manually if needed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Apache DolphinScheduler provides two production-ready alternatives to ZooKeeper: &lt;strong&gt;JDBC Registry&lt;/strong&gt; and &lt;strong&gt;Etcd Registry&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Both implementations support the same core capabilities required by a distributed scheduler, including service registration, service discovery, event notification, heartbeat management, and distributed locking.&lt;/p&gt;

&lt;p&gt;The JDBC Registry is particularly attractive for teams with mature relational database infrastructure, while the Etcd Registry offers a seamless experience for organizations embracing Kubernetes and cloud-native technologies.&lt;/p&gt;

&lt;p&gt;Instead of forcing every deployment to depend on a single coordination service, DolphinScheduler allows users to make infrastructure decisions based on their own operational requirements.&lt;/p&gt;

&lt;p&gt;This flexibility reflects one of the project's core principles: software should adapt to its users—not the other way around.&lt;/p&gt;

&lt;p&gt;As distributed systems continue to evolve, reducing unnecessary dependencies while providing deployment choices becomes increasingly valuable. By supporting multiple registry implementations, Apache DolphinScheduler enables organizations to build reliable scheduling platforms using the technologies they already know and trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;ZooKeeper remains the default registry implementation in Apache DolphinScheduler and has &lt;strong&gt;not&lt;/strong&gt; been deprecated.&lt;/li&gt;
&lt;li&gt;By default, the JDBC Registry uses the same database as DolphinScheduler metadata, although a separate database can also be configured.&lt;/li&gt;
&lt;li&gt;The Etcd Registry supports both SSL/TLS encryption and user authentication, allowing deployments to meet different security requirements.&lt;/li&gt;
&lt;li&gt;In pseudo-cluster deployments, users can choose among ZooKeeper, MySQL (JDBC Registry), and Etcd as the registry implementation.&lt;/li&gt;
&lt;li&gt;All registry configurations support environment variables, making them easy to integrate into containerized and cloud-native deployment workflows.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>apachedolphinscheduler</category>
      <category>zookeeper</category>
      <category>datascience</category>
      <category>bigdata</category>
    </item>
    <item>
      <title>How to Run Apache Flink Kafka Jobs with Apache DolphinScheduler on Linux</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Thu, 02 Jul 2026 07:18:06 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/how-to-run-apache-flink-kafka-jobs-with-apache-dolphinscheduler-on-linux-36k</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/how-to-run-apache-flink-kafka-jobs-with-apache-dolphinscheduler-on-linux-36k</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5tf8rdeto5szpx6nwa9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb5tf8rdeto5szpx6nwa9.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apache DolphinScheduler has already been deployed on a virtual machine.&lt;br&gt;
Next, we want to try creating a Flink task node in DolphinScheduler and use Flink to consume data from Kafka.&lt;/p&gt;

&lt;p&gt;Apache DolphinScheduler is deployed in &lt;strong&gt;standalone mode&lt;/strong&gt;.&lt;br&gt;
For detailed installation steps, please refer to the official documentation:&lt;br&gt;
DolphinScheduler | Documentation Center&lt;br&gt;
&lt;a href="https://dolphinscheduler.apache.org/zh-cn/docs/3.3.2/guide/installation/standalone" rel="noopener noreferrer"&gt;https://dolphinscheduler.apache.org/zh-cn/docs/3.3.2/guide/installation/standalone&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;The following components have already been installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java 11&lt;/li&gt;
&lt;li&gt;Apache DolphinScheduler 3.3.2&lt;/li&gt;
&lt;li&gt;Apache Flink 1.18.1&lt;/li&gt;
&lt;li&gt;Apache Kafka 3.6.0&lt;/li&gt;
&lt;li&gt;ZooKeeper (using the built-in Kafka version)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is recommended to download and install &lt;strong&gt;binary packages&lt;/strong&gt; directly on the virtual machine. Installing via system package managers may introduce uncontrollable dependencies.&lt;/p&gt;

&lt;p&gt;The downloaded binary packages are shown below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwxn5hu5my14a9cb248yi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwxn5hu5my14a9cb248yi.jpg" width="305" height="177"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Configure Flink Environment Variables
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Edit environment variables
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vim ~/.bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Add the Flink installation path:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fddfsb81wr7e7fd8y3hi3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fddfsb81wr7e7fd8y3hi3.jpg" width="800" height="453"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Make the configuration effective
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Reload environment variables&lt;/span&gt;
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.bashrc

&lt;span class="c"&gt;# Verify Flink environment variable&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$Flink_HOME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Modify Kafka, Flink, and DolphinScheduler Configuration Files
&lt;/h2&gt;

&lt;p&gt;Since this setup runs inside a virtual machine, configuration changes are required so that services can be accessed from the host machine.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Modify Kafka configuration
&lt;/h3&gt;

&lt;p&gt;Navigate to the &lt;code&gt;config&lt;/code&gt; directory under the Kafka installation path and edit &lt;code&gt;server.properties&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;listeners&lt;/code&gt; and &lt;code&gt;advertised.listeners&lt;/code&gt; settings must be modified so that Kafka can be accessed externally. Otherwise, Kafka will default to &lt;code&gt;localhost&lt;/code&gt;, which may cause connection failures.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;broker.id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;
&lt;span class="py"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;PLAINTEXT://0.0.0.0:9092&lt;/span&gt;
&lt;span class="c"&gt;# Replace with your VM IP address
&lt;/span&gt;&lt;span class="py"&gt;advertised.listeners&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;PLAINTEXT://192.168.146.132:9092&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4gitszod65cna1mbwat3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4gitszod65cna1mbwat3.jpg" width="800" height="267"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Modify Flink configuration
&lt;/h3&gt;

&lt;p&gt;Go to the &lt;code&gt;conf&lt;/code&gt; directory under the Flink installation path and edit &lt;code&gt;flink-conf.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Replace all &lt;code&gt;localhost&lt;/code&gt; addresses with &lt;code&gt;0.0.0.0&lt;/code&gt; so the Flink Web UI can be accessed externally.&lt;br&gt;
Additionally, adjust JobManager and TaskManager memory settings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobmanager.rpc.address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
&lt;span class="na"&gt;jobmanager.bind-host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
&lt;span class="na"&gt;jobmanager.cpu.cores&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="na"&gt;jobmanager.memory.process.size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1600m&lt;/span&gt;

&lt;span class="na"&gt;taskmanager.bind-host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
&lt;span class="na"&gt;taskmanager.host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;0.0.0.0&lt;/span&gt;
&lt;span class="na"&gt;taskmanager.memory.process.size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2048m&lt;/span&gt;
&lt;span class="na"&gt;taskmanager.cpu.cores&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4im9ovoeaa4s49w9ymj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw4im9ovoeaa4s49w9ymj.jpg" width="800" height="458"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl164gorhlrr2iwea71ha.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl164gorhlrr2iwea71ha.jpg" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Modify Apache DolphinScheduler configuration
&lt;/h3&gt;

&lt;p&gt;From the &lt;code&gt;dolphinscheduler-daemon.sh&lt;/code&gt; startup script, we can see that DolphinScheduler loads environment variables from:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bin/env/dolphinscheduler_env.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;View &lt;code&gt;dolphinscheduler-daemon.sh&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffbtf4z500p5ag7jeg6i2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffbtf4z500p5ag7jeg6i2.jpg" width="800" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Edit &lt;code&gt;dolphinscheduler_env.sh&lt;/code&gt; and add Java and Flink paths:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Replace with your actual Java and Flink paths&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;JAVA_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/data/jdk-11.0.29
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;Flink_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/data/Flink-1.18.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0h0lam2x8e4lye3ozect.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0h0lam2x8e4lye3ozect.jpg" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Disable Firewall and Start Services
&lt;/h2&gt;

&lt;p&gt;Start all required services, including ZooKeeper, Kafka, Flink, and Apache DolphinScheduler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Disable firewall&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl stop firewalld

&lt;span class="c"&gt;# Start Flink cluster&lt;/span&gt;
bin/start-cluster.sh

&lt;span class="c"&gt;# Start ZooKeeper&lt;/span&gt;
bin/zookeeper-server-start.sh config/zookeeper.properties &amp;amp;

&lt;span class="c"&gt;# Start Kafka broker&lt;/span&gt;
bin/kafka-server-start.sh config/server.properties &amp;amp;

&lt;span class="c"&gt;# Create Kafka topic&lt;/span&gt;
bin/kafka-topics.sh &lt;span class="nt"&gt;--create&lt;/span&gt; &lt;span class="nt"&gt;--topic&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--partitions&lt;/span&gt; 1 &lt;span class="nt"&gt;--replication-factor&lt;/span&gt; 1

&lt;span class="c"&gt;# Produce messages&lt;/span&gt;
bin/kafka-console-producer.sh &lt;span class="nt"&gt;--topic&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092

&lt;span class="c"&gt;# Consume messages&lt;/span&gt;
bin/kafka-console-consumer.sh &lt;span class="nt"&gt;--topic&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--from-beginning&lt;/span&gt; &lt;span class="nt"&gt;--bootstrap-server&lt;/span&gt; localhost:9092

&lt;span class="c"&gt;# Start DolphinScheduler Standalone Server&lt;/span&gt;
bash ./bin/dolphinscheduler-daemon.sh start standalone-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Verify Flink Web UI
&lt;/h3&gt;

&lt;p&gt;Access the Flink dashboard at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;VM-IP&amp;gt;:8081
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9j1j8eszyyb2dtmboc5n.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9j1j8eszyyb2dtmboc5n.jpg" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Verify DolphinScheduler Web UI
&lt;/h3&gt;

&lt;p&gt;Access DolphinScheduler at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;VM-IP&amp;gt;:12345/dolphinscheduler/ui
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Default credentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Username: &lt;code&gt;admin&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Password: &lt;code&gt;dolphinscheduler123&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sample Implementation
&lt;/h2&gt;

&lt;p&gt;This example demonstrates how Flink consumes data from Kafka, packages the job, uploads it to DolphinScheduler, and executes it as a Flink task.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Sample Code
&lt;/h3&gt;

&lt;h4&gt;
  
  
  pom.xml
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&amp;gt;
    &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;

    &amp;lt;groupId&amp;gt;com.example&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;Flink-Kafka-demo&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;1.0-SNAPSHOT&amp;lt;/version&amp;gt;

    &amp;lt;properties&amp;gt;
        &amp;lt;project.build.sourceEncoding&amp;gt;UTF-8&amp;lt;/project.build.sourceEncoding&amp;gt;
        &amp;lt;maven.compiler.source&amp;gt;1.8&amp;lt;/maven.compiler.source&amp;gt;
        &amp;lt;maven.compiler.target&amp;gt;1.8&amp;lt;/maven.compiler.target&amp;gt;
        &amp;lt;Flink.version&amp;gt;1.18.1&amp;lt;/Flink.version&amp;gt;
        &amp;lt;scala.binary.version&amp;gt;2.12&amp;lt;/scala.binary.version&amp;gt;
        &amp;lt;Kafka.version&amp;gt;3.6.0&amp;lt;/Kafka.version&amp;gt;
    &amp;lt;/properties&amp;gt;

    &amp;lt;dependencies&amp;gt;
        &amp;lt;!-- Flink core dependency --&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.Flink&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;Flink-java&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${Flink.version}&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.Flink&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;Flink-streaming-java&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${Flink.version}&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.Flink&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;Flink-clients&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${Flink.version}&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;

        &amp;lt;!-- Connector Base Dependency --&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.Flink&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;Flink-connector-base&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${Flink.version}&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;

        &amp;lt;!-- Kafka Connector (Key Change) --&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.Flink&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;Flink-connector-Kafka&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;3.1.0-1.18&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.Kafka&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;Kafka-clients&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;${Kafka.version}&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;

        &amp;lt;!-- Logging Dependency --&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;slf4j-simple&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;1.7.36&amp;lt;/version&amp;gt;
            &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
        &amp;lt;/dependency&amp;gt;
    &amp;lt;/dependencies&amp;gt;

    &amp;lt;repositories&amp;gt;
        &amp;lt;repository&amp;gt;
            &amp;lt;id&amp;gt;aliyun&amp;lt;/id&amp;gt;
            &amp;lt;url&amp;gt;https://maven.aliyun.com/repository/public&amp;lt;/url&amp;gt;
            &amp;lt;releases&amp;gt;
                &amp;lt;enabled&amp;gt;true&amp;lt;/enabled&amp;gt;
            &amp;lt;/releases&amp;gt;
            &amp;lt;snapshots&amp;gt;
                &amp;lt;enabled&amp;gt;false&amp;lt;/enabled&amp;gt;
            &amp;lt;/snapshots&amp;gt;
        &amp;lt;/repository&amp;gt;
        &amp;lt;repository&amp;gt;
            &amp;lt;id&amp;gt;apache-releases&amp;lt;/id&amp;gt;
            &amp;lt;url&amp;gt;https://repository.apache.org/content/repositories/releases/&amp;lt;/url&amp;gt;
        &amp;lt;/repository&amp;gt;
    &amp;lt;/repositories&amp;gt;

    &amp;lt;build&amp;gt;
        &amp;lt;plugins&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;3.8.1&amp;lt;/version&amp;gt;
                &amp;lt;configuration&amp;gt;
                    &amp;lt;source&amp;gt;${maven.compiler.source}&amp;lt;/source&amp;gt;
                    &amp;lt;target&amp;gt;${maven.compiler.target}&amp;lt;/target&amp;gt;
                &amp;lt;/configuration&amp;gt;
            &amp;lt;/plugin&amp;gt;
            &amp;lt;plugin&amp;gt;
                &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
                &amp;lt;artifactId&amp;gt;maven-shade-plugin&amp;lt;/artifactId&amp;gt;
                &amp;lt;version&amp;gt;3.2.4&amp;lt;/version&amp;gt;
                &amp;lt;executions&amp;gt;
                    &amp;lt;execution&amp;gt;
                        &amp;lt;phase&amp;gt;package&amp;lt;/phase&amp;gt;
                        &amp;lt;goals&amp;gt;
                            &amp;lt;goal&amp;gt;shade&amp;lt;/goal&amp;gt;
                        &amp;lt;/goals&amp;gt;
                        &amp;lt;configuration&amp;gt;
                            &amp;lt;artifactSet&amp;gt;
                                &amp;lt;excludes&amp;gt;
                                    &amp;lt;exclude&amp;gt;org.apache.Flink:force-shading&amp;lt;/exclude&amp;gt;
                                    &amp;lt;exclude&amp;gt;com.google.code.findbugs:jsr305&amp;lt;/exclude&amp;gt;
                                    &amp;lt;exclude&amp;gt;org.slf4j:*&amp;lt;/exclude&amp;gt;
                                &amp;lt;/excludes&amp;gt;
                            &amp;lt;/artifactSet&amp;gt;
                            &amp;lt;filters&amp;gt;
                                &amp;lt;filter&amp;gt;
                                    &amp;lt;artifact&amp;gt;*:*&amp;lt;/artifact&amp;gt;
                                    &amp;lt;excludes&amp;gt;
                                        &amp;lt;exclude&amp;gt;META-INF/*.SF&amp;lt;/exclude&amp;gt;
                                        &amp;lt;exclude&amp;gt;META-INF/*.DSA&amp;lt;/exclude&amp;gt;
                                        &amp;lt;exclude&amp;gt;META-INF/*.RSA&amp;lt;/exclude&amp;gt;
                                    &amp;lt;/excludes&amp;gt;
                                &amp;lt;/filter&amp;gt;
                            &amp;lt;/filters&amp;gt;
                        &amp;lt;/configuration&amp;gt;
                    &amp;lt;/execution&amp;gt;
                &amp;lt;/executions&amp;gt;
            &amp;lt;/plugin&amp;gt;
        &amp;lt;/plugins&amp;gt;
    &amp;lt;/build&amp;gt;
&amp;lt;/project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  FlinkKafkaConsumerExample.java
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import org.apache.Flink.api.common.functions.FlatMapFunction;
import org.apache.Flink.api.java.tuple.Tuple2;
import org.apache.Flink.api.java.utils.ParameterTool;
import org.apache.Flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.Flink.streaming.api.datastream.DataStream;
import org.apache.Flink.streaming.api.functions.ProcessFunction;
import org.apache.Flink.streaming.api.functions.sink.RichSinkFunction;
import org.apache.Flink.util.Collector;
import org.apache.Flink.streaming.connectors.Kafka.FlinkKafkaConsumer;
import org.apache.Flink.api.common.serialization.SimpleStringSchema;
import org.apache.Kafka.clients.consumer.ConsumerConfig;
import org.apache.Kafka.common.serialization.StringDeserializer;

import java.util.Properties;
import java.util.concurrent.CompletableFuture;


public class FlinkKafkaConsumerExample {
    private static volatile int messageCount = 0;
    private static volatile boolean shouldStop = false;
    public static void main(String[] args) throws Exception {
        // Set the execution environment
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

        // Kafka configuration
        Properties properties = new Properties();
        properties.setProperty(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.146.132:9092"); // Kafka broker 地址
        properties.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "test-group"); // Consumer group
        properties.setProperty(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());
        properties.setProperty(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class.getName());

        // Create Kafka Consumer
        FlinkKafkaConsumer&amp;lt;String&amp;gt; KafkaConsumer = new FlinkKafkaConsumer&amp;lt;&amp;gt;("test", new SimpleStringSchema(), properties);
        KafkaConsumer.setStartFromEarliest(); // Consume from the earliest messages
        DataStream&amp;lt;String&amp;gt; stream = env.addSource(KafkaConsumer);

        // Process data: tokenization and counting
        DataStream&amp;lt;Tuple2&amp;lt;String, Integer&amp;gt;&amp;gt; counts = stream
                .flatMap(new Tokenizer())
                .keyBy(value -&amp;gt; value.f0)
                .sum(1);


        counts.addSink(new RichSinkFunction&amp;lt;Tuple2&amp;lt;String, Integer&amp;gt;&amp;gt;() {
            @Override
            public void invoke(Tuple2&amp;lt;String, Integer&amp;gt; value, Context context) {
                System.out.println(value);
                messageCount++;

                // Check whether the stop condition is met
                if (messageCount &amp;gt;= 2 &amp;amp;&amp;amp; !shouldStop) {
                    System.out.println("Processed 2 messages, stopping job.");
                    shouldStop = true; // Set a flag to indicate that the job should stop
                }
            }
        });

        // Execute the job and obtain JobClient
        CompletableFuture&amp;lt;Void&amp;gt; future = CompletableFuture.runAsync(() -&amp;gt; {
            try {
                // Start the job and obtain JobClient
                org.apache.Flink.core.execution.JobClient jobClient = env.executeAsync("Flink Kafka WordCount");
                System.out.println("Job ID: " + jobClient.getJobID());

                // Monitor the condition and cancel the job
                while (!shouldStop) {
                    Thread.sleep(100); // Check every 100 milliseconds
                }

                // Cancel the job when the stop condition is met
                if (shouldStop) {
                    System.out.println("Cancelling the job...");
                    jobClient.cancel().get(); // Cancel the job
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        // Wait for the job to finish in the main thread
        future.join(); // Wait for the job to finish
            }

    // Tokenizer Class for converting input strings into words
    public static final class Tokenizer implements FlatMapFunction&amp;lt;String, Tuple2&amp;lt;String, Integer&amp;gt;&amp;gt; {
        @Override
        public void flatMap(String value, Collector&amp;lt;Tuple2&amp;lt;String, Integer&amp;gt;&amp;gt; out) {
            String[] tokens = value.toLowerCase().split("\\W+");
            for (String token : tokens) {
                if (token.length() &amp;gt; 0) {
                    out.collect(new Tuple2&amp;lt;&amp;gt;(token, 1));
                }
            }
        }
    }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Package and Upload to DolphinScheduler
&lt;/h3&gt;

&lt;h3&gt;
  
  
  3. Create and Run a Flink Task Node
&lt;/h3&gt;

&lt;p&gt;Start the Kafka producer in the virtual machine and send messages.&lt;br&gt;
Flink successfully consumes and processes the Kafka data.&lt;/p&gt;

</description>
      <category>apachedolphinscheduler</category>
      <category>kafka</category>
      <category>linux</category>
      <category>java</category>
    </item>
    <item>
      <title>Demystifying DolphinScheduler’s Plugin Mechanism: Extend Task Types &amp; Data Sources with Ease</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Fri, 26 Jun 2026 09:04:48 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/demystifying-dolphinschedulers-plugin-mechanism-extend-task-types-data-sources-with-ease-2k7e</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/demystifying-dolphinschedulers-plugin-mechanism-extend-task-types-data-sources-with-ease-2k7e</guid>
      <description>&lt;h2&gt;
  
  
  1. High-Level Architecture Overview
&lt;/h2&gt;

&lt;p&gt;DolphinScheduler’s plugin ecosystem is built upon the Java SPI (Service Provider Interface) framework, paired with Google AutoService to auto-generate registration files, enabling non-intrusive plugin-based extension capabilities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dolphinscheduler-spi                    ← Core Interface Layer (SPI Infrastructure)
dolphinscheduler-datasource-plugin      ← Data Source Plugin Layer
dolphinscheduler-task-plugin            ← Task Plugin Layer
dolphinscheduler-worker                 ← Plugin Consumer Layer (Worker for task execution)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. SPI Core Infrastructure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PrioritySPI (Root Interface)
  └── getIdentify(): SPIIdentify  ← Unique plugin identifier + priority weight
  └── compareTo(Integer)          ← Priority comparison logic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;PrioritySPIFactory&amp;lt;T&amp;gt;&lt;/code&gt; acts as the core engine for plugin discovery&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Scan classpath via Java native ServiceLoader&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="no"&gt;T&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ServiceLoader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spiClass&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;containsKey&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIdentify&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;()))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;resolveConflict&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// Resolve duplicate plugins by priority; throw exception if priorities match&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getIdentify&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Plugin Registration Mechanism&lt;/strong&gt;: Each plugin module leverages the &lt;code&gt;@AutoService&lt;/code&gt; annotation. During compilation, SPI configuration files are automatically generated under the &lt;code&gt;META-INF/services/&lt;/code&gt; directory, eliminating manual config maintenance.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Deep Dive into Data Source Plugin Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Interface Hierarchy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DataSourceChannelFactory (SPI Entry Point)
  └── getName()          ← Unique plugin identifier, e.g. "MYSQL"
  └── create()           ← Instantiate DataSourceChannel

DataSourceChannel (Connection Channel)
  └── createAdHocDataSourceClient()    ← Create one-off temporary connection client
  └── createPooledDataSourceClient()   ← Create pooled connection client

DataSourceClient (Base Interface)
  └── getConnection(): Connection

PooledDataSourceClient extends DataSourceClient
  └── createDataSourcePool()           ← Initialize HikariCP connection pool
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.2 End-to-End Implementation Example: MySQL Plugin
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MySQLDataSourceChannelFactory          ← Registered via @AutoService annotation
  └── create() → MySQLDataSourceChannel
        └── createPooledDataSourceClient() → MySQLPooledDataSourceClient
              └── extends BasePooledDataSourceClient
                    └── createDataSourcePool() → HikariDataSource
                          ├── setDriverClassName()
                          ├── setJdbcUrl()
                          ├── setUsername() / setPassword()
                          ├── setMinimumIdle() / setMaximumPoolSize()
                          └── setConnectionTestQuery()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Deep Dive into Task Plugin Workflow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Interface Hierarchy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TaskChannelFactory (SPI Entry Point) extends UiChannelFactory, PrioritySPI
  └── getName()          ← Unique task type identifier, e.g. "SHELL"
  └── create()           ← Instantiate TaskChannel
  └── getParams()        ← Return UI configuration parameters for frontend rendering

TaskChannel (Task Execution Channel)
  └── createTask(TaskExecutionContext) → AbstractTask
  └── parseParameters(ParametersNode) → AbstractParameters
  └── getResources(parameters)        → ResourceParametersHelper
  └── cancelApplication(boolean)

AbstractTask (Base Task Execution Class)
  └── init()             ← Task initialization logic
  └── handle(callback)   ← Core execution logic (abstract method)
  └── cancel()           ← Task termination logic (abstract method)
  └── getExitStatus()    ← Map exit code to standardized task status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 End-to-End Implementation Example: Shell Task Plugin
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ShellTaskChannelFactory                ← Registered via @AutoService annotation
  └── getName() → "SHELL"
  └── getParams() → [nodeName, runFlag, ...]  ← Frontend UI configuration fields
  └── create() → ShellTaskChannel
        └── createTask(ctx) → ShellTask
              └── handle(callback)
                    └── ShellCommandExecutor.run(shellActuatorBuilder)
                          └── Spawn &amp;amp; execute shell script process
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  5. Side-by-Side Comparison of Two Plugin Types
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Redshift Concurrency Scaling&lt;/th&gt;
&lt;th&gt;DolphinScheduler Task Groups&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control Granularity&lt;/td&gt;
&lt;td&gt;Cluster-level, auto-scaling&lt;/td&gt;
&lt;td&gt;Task/Workflow-level, manual control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modification Cost&lt;/td&gt;
&lt;td&gt;Low; only parameter configuration required&lt;/td&gt;
&lt;td&gt;Medium; task grouping planning needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost Impact&lt;/td&gt;
&lt;td&gt;Pay-as-you-go, potential extra charges&lt;/td&gt;
&lt;td&gt;No additional fees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Applicable Scenarios&lt;/td&gt;
&lt;td&gt;Sudden, unpredictable load spikes&lt;/td&gt;
&lt;td&gt;Known, stable high-concurrency scheduling scenarios&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recommended Usage&lt;/td&gt;
&lt;td&gt;Acts as a "fuse" to handle unexpected traffic surges&lt;/td&gt;
&lt;td&gt;Acts as a "throttle valve" for daily concurrency governance&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

</description>
      <category>apachedolphinscheduler</category>
      <category>opensource</category>
      <category>programming</category>
      <category>developer</category>
    </item>
    <item>
      <title>Apache DolphinScheduler + AWS Data Lakehouse: Practical Hybrid Scheduling &amp; Cloud Cost Optimization Guide</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Fri, 26 Jun 2026 08:14:28 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/apache-dolphinscheduler-aws-data-lakehouse-practical-hybrid-scheduling-cloud-cost-optimization-25o2</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/apache-dolphinscheduler-aws-data-lakehouse-practical-hybrid-scheduling-cloud-cost-optimization-25o2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpg7wthi5ytvmqtvjmxj2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpg7wthi5ytvmqtvjmxj2.jpg" width="799" height="369"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Project Overview: Apache DolphinScheduler Meets AWS Data Lakehouse
&lt;/h2&gt;

&lt;p&gt;As data-driven business decision-making becomes mainstream across industries, a high-performance, flexible, cost-efficient data-processing pipeline is the core competitive edge of enterprise data platforms. I’ve collaborated with numerous engineering teams that initially built on-premises Hadoop clusters paired with self-maintained scheduling systems. However, skyrocketing data volumes and growing business complexity have exposed severe bottlenecks in this legacy architecture: lengthy resource scaling cycles, excessive operational overhead, rigid task orchestration logic, and most critically, a lack of balanced performance-cost tradeoffs.&lt;/p&gt;

&lt;p&gt;Mature cloud-native data architectures—especially AWS’s full-spectrum suite spanning Amazon S3 data lakes, Amazon Redshift data warehouses, and Amazon EMR big-data processing engines—have delivered a transformative solution to these pain points. Simply migrating standalone components to the cloud is insufficient; seamless interoperability and unified orchestration of these services are the real keys to unlocking the cloud platform's potential. This is where Apache DolphinScheduler, an open-source distributed visual workflow task scheduler, delivers unmatched value. Acting as a unified "data pipeline conductor", it coordinates Amazon EMR for large-scale batch data processing and orchestrates Amazon Redshift to power high-performance analytical queries.&lt;/p&gt;

&lt;p&gt;Drawing from a real customer cloud migration and optimization project, this article delivers an in-depth breakdown of deep DolphinScheduler integration within AWS’s Intelligent Data Lakehouse framework. We focus on two core practical scenarios: hybrid scheduling and cost optimization for Amazon EMR (covering traditional EC2-backed clusters and serverless EMR runtime), plus reliable, secure Amazon Redshift task orchestration with built-in mitigations for Redshift’s native concurrency limits. Whether you are a data platform engineer planning cloud migration or an architect aiming to boost efficiency for existing cloud-based data pipelines, the battle-tested patterns, production-ready code snippets, and troubleshooting insights shared in this hands-on guide will deliver actionable, immediate value.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Architecture &amp;amp; Tool Selection: Why DolphinScheduler + AWS Is the Optimal Combination
&lt;/h2&gt;

&lt;p&gt;Before diving into hands-on implementation, we first unpack the rationale behind this tech stack pairing: what unique benefits AWS and Apache DolphinScheduler each bring, and which core pain points their combined architecture resolves. Clear alignment on these foundational design decisions streamlines subsequent deployment and customization workstreams.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Deep Dive into AWS Intelligent Data Lakehouse Architecture
&lt;/h3&gt;

&lt;p&gt;AWS’s Intelligent Data Lakehouse is not a single monolithic product, but a set of industry best practices centered on Amazon S3 as the universal data lake storage layer. Its core design principle eliminates data silos, enabling secure, frictionless data movement across storage, batch processing, real-time analytics, and machine learning workloads.&lt;/p&gt;

&lt;p&gt;Within this ecosystem, Amazon S3 acts as infinitely scalable centralized storage for all raw and refined datasets. A suite of fully managed AWS services operates alongside S3 with specialized, decoupled responsibilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data Ingestion&lt;/strong&gt;: Amazon Kinesis for real-time streaming pipelines, Amazon MSK (Managed Streaming for Apache Kafka) for persistent stream processing, and AWS Glue for serverless ETL and centralized data catalog governance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Big Data Batch Processing&lt;/strong&gt;: Amazon EMR serves as the primary compute layer, offering managed deployments of open-source frameworks including Apache Spark, Apache Hive, and Apache Flink for data cleansing, transformation, and complex distributed computing jobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Warehousing &amp;amp; BI Analytics&lt;/strong&gt;: Amazon Redshift delivers high-performance petabyte-scale cloud data warehousing, powering complex aggregated queries, business intelligence dashboards, and ad-hoc analytical workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Machine Learning &amp;amp; AI&lt;/strong&gt;: Amazon SageMaker natively accesses datasets stored in S3 and Redshift to run model training, validation, and real-time inference pipelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The "intelligent" differentiator of this architecture lies in native cross-service integration: Amazon EMR and Redshift directly read S3 datasets without costly data duplication or movement, while the AWS Glue Data Catalog functions as a unified metadata store shared across EMR, Redshift, and Amazon Athena. Our core integration challenge lies in building a single orchestration layer capable of reliably sequencing, monitoring, and governing disparate workloads running across all these managed AWS services.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Core Value &amp;amp; Strategic Positioning of Apache DolphinScheduler
&lt;/h3&gt;

&lt;p&gt;Apache DolphinScheduler is a distributed, visual workflow scheduling platform built for data engineering teams. It outperforms legacy scheduling tools such as cron jobs and custom shell script orchestration via the following key capabilities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Visual DAG Orchestration&lt;/strong&gt;: Drag-and-drop canvas construction of complex Directed Acyclic Graph (DAG) workflows, rendering upstream/downstream task dependencies fully transparent and lowering barriers for citizen data developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-Grade Reliability &amp;amp; HA&lt;/strong&gt;: Decentralized Master-Worker cluster architecture supporting horizontal elastic scaling; single-node failures do not halt overall platform availability, with native task retry logic, timeout controls, and multi-channel alerting built in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Tenant Isolation &amp;amp; Fine-Grained RBAC&lt;/strong&gt;: Resource segmentation and permission controls organized by project and user team, ideal for collaborative enterprise data teams across departments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extensive Native Task Types &amp;amp; Plugin Ecosystem&lt;/strong&gt;: Out-of-the-box support for Shell, Python, generic SQL, Apache Spark, Apache Flink, and additional task runtimes, paired with a robust plugin extension framework—this extensibility forms the technical foundation for deep native integration with AWS managed services.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Within the AWS data lakehouse stack, DolphinScheduler functions exclusively as the unified orchestration plane. It does not replace EMR’s distributed compute capacity or Redshift’s analytical query engine; instead, it operates at a higher abstraction layer to govern critical execution logic: defining timelines, injecting dynamic runtime parameters, routing Spark and Redshift SQL jobs to designated compute resources (EC2-based EMR clusters, EMR Serverless, Redshift warehouses), and monitoring full task lifecycles end-to-end.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Hybrid Compute Resource Routing Strategy Design
&lt;/h3&gt;

&lt;p&gt;Following their migration from on-premises Hadoop to Amazon EMR on EC2, the customer initially ran all workloads on persistent EC2-backed EMR clusters. They quickly identified severe cost inefficiencies stemming from uneven resource utilization driven by highly variable job load patterns, split into three distinct workload categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small, Short-Lived Jobs&lt;/strong&gt;: High volume of lightweight tasks with 20–30 minute average runtime, triggered sporadically around the clock. Provisioning full multi-node EMR clusters for these micro-jobs creates massive idle resource waste, analogous to deploying heavy artillery to eliminate minor targets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Medium-Dense Daily Batch Jobs&lt;/strong&gt;: Compute-heavy workloads executing within a fixed 7–8 hour daily processing window, suited for dedicated EMR clusters—yet persistent cluster provisioning incurs idle-hour billing outside the scheduled execution window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Massive Infrequent Batch Jobs&lt;/strong&gt;: Multi-day long-running calculations executed only 2–3 times monthly; maintaining dedicated persistent clusters for these rare workloads generates prohibitive recurring cloud costs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To address this imbalance, we implemented a &lt;strong&gt;hybrid intelligent workload routing strategy&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small sporadic jobs + rare long-running massive jobs → EMR Serverless&lt;/strong&gt;: AWS EMR Serverless eliminates cluster provisioning and infrastructure management overhead entirely; users only submit jobs and pay per consumed vCPU and memory second. This runtime perfectly aligns with sporadic, bursty workload patterns: micro-jobs avoid persistent cluster idle fees, while infrequent long-running jobs eliminate the cost of permanently reserved compute infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fixed-window medium-dense daily jobs → Time-bound auto-start/auto-terminate EMR on EC2 clusters&lt;/strong&gt;: For predictable daily batch windows, we retain EC2-backed EMR clusters but automate full cluster lifecycle management via DolphinScheduler: clusters spin up automatically before workflow execution begins and terminate entirely once all daily tasks complete. Supplementing core task nodes with EC2 Spot Instances further cuts compute costs by 60–70%.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The foundational requirement enabling this strategy is DolphinScheduler’s custom intelligent workload routing capability: workflows must automatically route tasks to either EMR Serverless or persistent EMR EC2 clusters based on pre-defined task metadata tags and resource demand profiles. This required targeted custom development to wrap standardized, abstracted job submission interfaces within DolphinScheduler.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Integration Practice: Unified API Wrapper for EMR Orchestration
&lt;/h2&gt;

&lt;p&gt;While the hybrid routing strategy delivers clear cost benefits, critical API and runtime behavioral disparities between EMR on EC2 and EMR Serverless present the primary integration roadblock. Our core design objective is full workload transparency for data developers: engineers author tasks in DolphinScheduler without needing to identify the underlying EMR runtime executing their code.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Core Integration Challenges: Four Key Disparities Between EMR Runtime Modes
&lt;/h3&gt;

&lt;p&gt;Four fundamental technical differences complicate unified orchestration across the two EMR variants:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Job Submission &amp;amp; Synchronization Semantics&lt;/strong&gt;: EMR on EC2 Step APIs operate in semi-synchronous mode, supporting blocking execution waits with straightforward final status polling logic. EMR Serverless job submission APIs operate fully asynchronously: job IDs return instantly post-submission, requiring separate repeated API polling to retrieve real-time job status—creating compatibility gaps for schedulers reliant on synchronous task execution to trigger downstream DAG branches based on upstream success/failure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging Persistence Paths&lt;/strong&gt;: EMR on EC2 logs store outputs locally on cluster master nodes or HDFS, with optional CloudWatch Logs forwarding. EMR Serverless enforces mandatory log export to designated Amazon S3 prefixes, with entirely distinct log retrieval endpoints and file structures across the two runtimes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Divergent AWS SDK Interfaces&lt;/strong&gt;: Separate boto3 SDK clients govern each service (&lt;code&gt;emr&lt;/code&gt; client for EC2 clusters, &lt;code&gt;emr-serverless&lt;/code&gt; client for serverless jobs), with mismatched parameter schemas, argument naming conventions, and response payload structures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native SQL Support Gaps&lt;/strong&gt;: EMR on EC2 natively accepts inline SQL strings via Spark SQL or Hive Step definitions. Early EMR Serverless releases lacked direct inline SQL submission, requiring all SQL logic to be wrapped within standalone Spark script files uploaded to S3 prior to job launch.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Forcing developers to maintain dual code paths for each EMR runtime would introduce excessive operational complexity and technical debt. Our resolution is building a centralized abstracted Python SDK named &lt;code&gt;emr_common&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2 Implementation: Build a Unified Abstraction Python SDK
&lt;/h3&gt;

&lt;p&gt;We developed the open internal &lt;code&gt;emr_common&lt;/code&gt; Python library centered on a standardized top-level &lt;code&gt;Session&lt;/code&gt; factory class. This factory initializes specialized child session objects (&lt;code&gt;EMRSession&lt;/code&gt; or &lt;code&gt;EMRServerlessSession&lt;/code&gt;) based on an input &lt;code&gt;job_type&lt;/code&gt; parameter while exposing identical standardized public methods to upstream consumers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# emr_common/session.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;abc&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;abstractmethod&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BaseEMRSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ABC&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Abstract base class for unified EMR runtime sessions&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="nd"&gt;@abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit_sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="nd"&gt;@abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="nd"&gt;@abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="nd"&gt;@abstractmethod&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_logs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EMRSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseEMRSession&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Concrete implementation for EMR on EC2 clusters&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cluster_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;emr&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Auto-locate active waiting clusters if no explicit cluster ID provided
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cluster_id&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_find_active_cluster&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit_sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Construct standard EMR Step input parameters
&lt;/span&gt;        &lt;span class="n"&gt;step_args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;spark-sql&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;-e&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;sql&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_job_flow_steps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;JobFlowId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cluster_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ActionOnFailure&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;CONTINUE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;HadoopJarStep&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Jar&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;command-runner.jar&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Args&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;step_args&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}]&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;StepIds&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Supplementary method implementations: submit_file, get_status, get_logs omitted for brevity
&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EMRServerlessSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseEMRSession&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Concrete implementation for EMR Serverless applications&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;application_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;emr-serverless&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;application_id&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_find_active_application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit_sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Wrap raw SQL inside temporary PySpark script (required limitation for EMR Serverless)
&lt;/span&gt;        &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;NamedTemporaryFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suffix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.py&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
from pyspark.sql import SparkSession
spark = SparkSession.builder.appName(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;).getOrCreate()
spark.sql(&lt;/span&gt;&lt;span class="se"&gt;\"\"\"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"\"\"&lt;/span&gt;&lt;span class="s"&gt;)
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;script_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;
        &lt;span class="c1"&gt;# Internal helper function to upload local script to target S3 bucket
&lt;/span&gt;        &lt;span class="n"&gt;s3_script_uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;_upload_to_s3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;script_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s3_script_uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;submit_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Construct standardized EMR Serverless job request payload
&lt;/span&gt;        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_job_run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;applicationId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;application_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;executionRoleArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;arn:aws:iam::xxx:role/EMRServerlessRole&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;jobDriver&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sparkSubmit&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;entryPoint&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sparkSubmitParameters&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;--conf spark.executor.memory=4g&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;configurationOverrides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{...},&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;job_name&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;jobRunId&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Supplementary method implementations: get_status, get_logs with async polling &amp;amp; S3 log parsing omitted for brevity
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Factory function returning standardized EMR session instance&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;job_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;EMRSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;job_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;EMRServerlessSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unsupported job_type input value: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job_type&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Key architectural design highlights of the abstraction layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Synchronous Wrapper for Asynchronous Serverless APIs&lt;/strong&gt;: The &lt;code&gt;EMRServerlessSession.get_status()&lt;/code&gt; method encapsulates configurable interval polling logic with blocking execution until job completion or terminal failure status, delivering synchronous execution semantics to upstream DolphinScheduler workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unified Standardized Log Retrieval&lt;/strong&gt;: The shared &lt;code&gt;get_logs()&lt;/code&gt; abstract method internally detects the underlying EMR runtime, fetching logs from S3 prefixes for Serverless workloads or CloudWatch/local cluster storage for EC2-backed EMR jobs, and returns consistently formatted log output for centralized troubleshooting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intelligent Default Fallback Logic&lt;/strong&gt;: When users omit explicit &lt;code&gt;cluster_id&lt;/code&gt; or &lt;code&gt;application_id&lt;/code&gt; inputs, the SDK automatically scans the target AWS account/region for idle &lt;code&gt;WAITING&lt;/code&gt; or &lt;code&gt;STARTED&lt;/code&gt; EMR resources, reducing mandatory configuration overhead for end developers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparent Spark Configuration Normalization&lt;/strong&gt;: A shared standardized configuration dictionary accepts generic tuning parameters including &lt;code&gt;driver_memory&lt;/code&gt; and &lt;code&gt;executor_cores&lt;/code&gt;, with the SDK internally translating these unified inputs into runtime-specific argument schemas required by each EMR variant.
### 3.3 End-User Workflow Implementation within Apache DolphinScheduler
Once the &lt;code&gt;emr_common&lt;/code&gt; abstraction SDK is packaged and deployed to all DolphinScheduler Worker nodes, orchestration becomes streamlined via DolphinScheduler’s native Python Operator task type.
&lt;strong&gt;Python Operator Task Template Supporting Dynamic EMR Runtime Routing&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Reusable task template dynamically switching EMR runtime based on workflow parameters
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;emr_common&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Session&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Retrieve routing parameter passed via DolphinScheduler custom node/workflow variables
&lt;/span&gt;    &lt;span class="c1"&gt;# emr_job_type: 0 = EMR on EC2, 1 = EMR Serverless
&lt;/span&gt;    &lt;span class="n"&gt;job_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;emr_job_type&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;task_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;task_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;default_data_processing_job&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Initialize standardized abstract EMR session
&lt;/span&gt;    &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;job_type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Example: Submit inline Spark SQL transformation job
&lt;/span&gt;    &lt;span class="n"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    SELECT date, count(*) as cnt
    FROM your_core_operational_table
    WHERE date = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;${bizdate}&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;  -- Native DolphinScheduler built-in business date parameter
    GROUP BY date
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;job_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit_sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;_daily_agg_sql&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Block execution with 30-second polling interval until terminal job state
&lt;/span&gt;    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait_for_completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Distributed compute job &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;job_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; completed with final status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Pull full execution logs for workflow failure troubleshooting
&lt;/span&gt;    &lt;span class="n"&gt;full_task_logs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_logs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;job_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Append critical log snippets to DolphinScheduler native task log storage
&lt;/span&gt;    &lt;span class="c1"&gt;# ...
&lt;/span&gt;
    &lt;span class="c1"&gt;# Trigger workflow success/failure exit codes aligned with job terminal state
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;SUCCESS&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Distributed compute job terminated with failure status: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Parse runtime parameters injected by DolphinScheduler task runtime
&lt;/span&gt;    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
    &lt;span class="n"&gt;input_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;task_execution_success&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;input_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;task_execution_success&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameterized Workflow Design Best Practice&lt;/strong&gt;: Global workflow variables or node-level custom parameters are defined within DolphinScheduler’s workflow editor. For instance, a top-level global variable &lt;code&gt;emr_engine&lt;/code&gt; defaults to the value &lt;code&gt;serverless&lt;/code&gt;. A lightweight mapping helper translates &lt;code&gt;serverless&lt;/code&gt; to &lt;code&gt;job_type=1&lt;/code&gt; and &lt;code&gt;ec2_cluster&lt;/code&gt; to &lt;code&gt;job_type=0&lt;/code&gt;. This design enables one-click global runtime switching for all tasks within an entire workflow by simply modifying a single global parameter, drastically accelerating cross-runtime testing and iterative optimization.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unified Metadata Governance Critical Note&lt;/strong&gt;: To enable seamless cross-runtime data access and consistent table schema visibility across EMR on EC2 and EMR Serverless workloads, organizations must standardize on the AWS Glue Data Catalog as the shared metadata repository. All EMR clusters and Serverless applications must be provisioned with Glue Catalog integration enabled during resource creation. This eliminates the operational burden of maintaining separate Hive metastores for distinct compute runtimes while guaranteeing identical database and table schemas visible to all data processing jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Amazon Redshift Task Orchestration &amp;amp; Concurrency Throttling Implementation
&lt;/h2&gt;

&lt;p&gt;Following EMR integration, we shift focus to orchestrating Amazon Redshift, AWS’s enterprise petabyte-scale columnar data warehouse optimized for complex aggregated analytical queries. Starting with DolphinScheduler 3.x releases, the platform’s built-in Datasource Center delivers native Amazon Redshift JDBC connectivity, enabling direct Redshift SQL execution via DolphinScheduler’s standard SQL Operator task type.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1 Basic Redshift Orchestration via DolphinScheduler SQL Operator
&lt;/h3&gt;

&lt;p&gt;This represents the most widely adopted, straightforward implementation pattern for Redshift workload scheduling. After completing Redshift data source configuration within DolphinScheduler’s web UI, users create dedicated SQL Operator nodes to execute data warehouse transformation logic.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step-by-Step Configuration &amp;amp; Critical Operational Notes
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Datasource Connection Setup&lt;/strong&gt;: Standard JDBC connection string format: &lt;code&gt;jdbc:redshift://[Redshift Cluster Endpoint]:[Port]/[Target Database Name]&lt;/code&gt;. The primary networking prerequisite is bidirectional connectivity between DolphinScheduler Worker nodes and the Redshift cluster VPC, requiring properly configured VPC peering links and security group inbound/outbound traffic rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Parameterized SQL Authoring&lt;/strong&gt;: The SQL editor supports DolphinScheduler’s native &lt;code&gt;${variable}&lt;/code&gt; syntax to reference built-in system parameters and upstream task output payloads, enabling fully dynamic templated warehouse queries.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Sample daily partitioned table refresh ETL script for Redshift&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;dws_user_daily_activity&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;biz_date&lt;/span&gt; &lt;span class="nb"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;daily_activity_count&lt;/span&gt; &lt;span class="nb"&gt;INT&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;DISTKEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SORTKEY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;biz_date&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;dws_user_daily_activity&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;biz_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'${bizdate}'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;dws_user_daily_activity&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="s1"&gt;'${bizdate}'&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;DATE&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;biz_date&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;daily_activity_count&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;ods_user_raw_operation_logs&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;event_date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'${bizdate}'&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Redshift-Specific Maintenance Automation&lt;/strong&gt;: Schedule periodic maintenance operations including &lt;code&gt;ANALYZE&lt;/code&gt; (to refresh table query statistics) and &lt;code&gt;VACUUM&lt;/code&gt; (to reclaim storage space and re-sort tables) as dedicated low-priority DolphinScheduler tasks, restricted to off-peak business maintenance windows to avoid query performance degradation.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Critical Operational Caveat: Redshift’s transaction semantics diverge sharply from OLTP relational databases; multi-statement &lt;code&gt;BEGIN; ... COMMIT;&lt;/code&gt; blocks exhibit inconsistent behavior when wrapping DDL operations or bulk DML inserts. Data engineers are advised to separate DDL (CREATE, ALTER, DROP) and bulk DML (INSERT, UPDATE, DELETE) logic into independent sequential DolphinScheduler tasks with explicit dependency links, mitigating table-level locking risks and unintended transaction rollbacks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  4.2 Resolving Redshift Concurrency Bottlenecks: Two Production-Grade Throttling Strategies
&lt;/h3&gt;

&lt;p&gt;Redshift’s MPP architecture delivers fast analytical query performance but enforces finite concurrency slots (default cluster limits typically cap at 50 concurrent query slots). Unregulated parallel task submission from DolphinScheduler’s large-scale batch workflows frequently exhausts available slots, triggering prolonged query queuing and intermittent task failures. We have validated two complementary mitigation strategies for production environments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Strategy 1: Enable Amazon Redshift Concurrency Scaling
&lt;/h4&gt;

&lt;p&gt;This managed AWS-native paid feature automatically provisions temporary auxiliary scaling clusters when primary cluster concurrency slots reach saturation, expanding maximum supported parallel query capacity up to 10x baseline limits. The primary advantage is fully transparent horizontal scaling, requiring zero modifications to DolphinScheduler workflows or SQL logic.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deployment Steps&lt;/strong&gt;: Modify the target Redshift cluster parameter group via AWS Console or API, setting &lt;code&gt;max_concurrency_scaling_clusters&lt;/code&gt; to a positive integer value (e.g., 5), paired with a CPU utilization threshold trigger for auto-scaling activation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Efficiency Analysis&lt;/strong&gt;: Auxiliary concurrency scaling clusters bill per-second at higher hourly rates than primary Redshift nodes. Teams must evaluate peak load duration and frequency to calculate total incremental spend. Our field experience confirms this solution delivers strong ROI for predictable daily morning BI report traffic spikes, eliminating the need to over-provision primary cluster capacity permanently for short-duration peak demand.
#### Strategy 2: Workload Throttling via DolphinScheduler Native Task Groups
This zero-additional-cost strategy delivers granular, fully controllable parallelism limits directly within the orchestration platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task Group Resource Creation&lt;/strong&gt;: Navigate to DolphinScheduler’s Resource Center to provision a dedicated task group (example label: &lt;code&gt;redshift_query_group&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enforce Parallelism Caps&lt;/strong&gt;: Configure a hard maximum concurrent task limit for the group (example value: 15). This threshold should sit comfortably below the Redshift cluster’s safe recommended concurrency ceiling, reserving spare slots for ad-hoc analyst BI tool connections outside scheduled batch pipelines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bind Redshift Workloads to the Controlled Group&lt;/strong&gt;: Assign all DolphinScheduler SQL Operator nodes executing Redshift queries to the defined throttled task group via node configuration panels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operational Outcome&lt;/strong&gt;: Even with hundreds of ready-to-execute Redshift tasks queued within the workflow, DolphinScheduler strictly caps parallel submission to the configured limit, protecting the Redshift warehouse from overwhelming query load and slot exhaustion.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Combined Strategy Recommendation &amp;amp; Comparative Analysis
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fptzcbbqaqjbp75ura8vv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fptzcbbqaqjbp75ura8vv.jpg" width="799" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our validated production best practice combines both controls simultaneously: baseline traffic is governed via DolphinScheduler task group parallelism limits, while enabling 1–2 concurrency scaling, auxiliary clusters act as a safety buffer to absorb unplanned ad-hoc analyst queries or abnormally long-running scheduled batch jobs consuming excessive concurrency slots.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Shell Operator Integration with Git CI/CD Pipelines
&lt;/h3&gt;

&lt;p&gt;Beyond the native SQL Operator, DolphinScheduler’s Shell Operator delivers flexible orchestration capabilities for teams maintaining version-controlled SQL script files stored in Git repositories, enabling end-to-end data engineering DevOps workflows.&lt;/p&gt;

&lt;h4&gt;
  
  
  Standard End-to-End Implementation Pattern
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Data developers author versioned Redshift SQL transformation scripts (e.g., &lt;code&gt;transform_sales_daily.sql&lt;/code&gt;) locally and commit finalized code to central Git repositories such as GitLab or GitHub.&lt;/li&gt;
&lt;li&gt;CI/CD automation pipelines (Jenkins, GitHub Actions) trigger post-code-merge artifact delivery, uploading validated SQL script files to a dedicated versioned Amazon S3 artifact bucket.&lt;/li&gt;
&lt;li&gt;A DolphinScheduler Shell Operator task executes the following runtime command to pull and execute remote S3-hosted SQL scripts with dynamic business date parameter injection:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Assumption: psql client pre-installed on all DolphinScheduler Worker nodes; AWS CLI S3 access configured via IAM roles&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PGPASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;redshift_password&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
psql &lt;span class="nt"&gt;-h&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;redshift_host&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;redshift_port&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;redshift_user&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;redshift_db&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-f&lt;/span&gt; s3://your-central-script-bucket/etl/transform_sales_daily.sql &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;bizdate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;bizdate&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;-f&lt;/code&gt; flag directs the psql client to fetch the SQL script file directly from the defined S3 URI, requiring the Redshift cluster IAM role to include read permissions for the target script bucket.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;-v&lt;/code&gt; argument injects runtime variables accessible within the SQL script via &lt;code&gt;:bizdate&lt;/code&gt; template syntax.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Advanced Integration with DolphinScheduler Resource Center&lt;/strong&gt;: A cleaner native alternative leverages DolphinScheduler’s built-in Resource Center, which can mount Amazon S3 buckets as persistent file storage via compatible third-party storage plugins. SQL scripts are uploaded, edited, and version-controlled directly through DolphinScheduler’s web UI, eliminating separate CI/CD artifact upload steps. Shell Operator tasks simply reference the internal Resource Center file path, with DolphinScheduler automatically handling remote file fetching during task initialization.&lt;/p&gt;

&lt;p&gt;This unified workflow tightly integrates orchestration (DolphinScheduler), source code version control (Git), continuous delivery automation (CI/CD runners), and object storage (Amazon S3), establishing a fully auditable, reproducible data engineering DevOps pipeline with immutable script version history.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Operations, Observability &amp;amp; Continuous Cloud Cost Optimization Playbook
&lt;/h2&gt;

&lt;p&gt;Deep integration between DolphinScheduler and distributed AWS managed services expands operational monitoring scope beyond individual standalone tools to full end-to-end pipeline observability. Additionally, AWS’s pay-as-you-go consumption model requires iterative, ongoing cost governance rather than one-time migration optimization efforts.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 End-to-End Pipeline Monitoring &amp;amp; Multi-Channel Alerting
&lt;/h3&gt;

&lt;p&gt;Task failures can originate from DolphinScheduler platform instability, inter-service networking errors, AWS compute resource exhaustion, or flawed transformation logic. Organizations must implement layered observability covering every architectural tier:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Native DolphinScheduler Platform Alerting&lt;/strong&gt;: Leverage the built-in alert framework to deliver notifications for task failures, execution timeouts, and workflow suspension via email, DingTalk, Slack, or generic webhook endpoints. Critical monitoring targets include workflow instance state and individual task runtime status.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS CloudWatch Managed Service Telemetry&lt;/strong&gt;:

&lt;ol&gt;
&lt;li&gt;Amazon EMR: Monitor metrics including &lt;code&gt;YARNMemoryAvailablePercentage&lt;/code&gt;, &lt;code&gt;ContainerPendingRatio&lt;/code&gt; to pre-empt compute resource starvation; track Step execution duration and success/failure ratios.&lt;/li&gt;
&lt;li&gt;EMR Serverless: Track JobRun success/failure rates, total wall-clock runtime, and consumed vCPU/memory resources (direct cost drivers for serverless billing).&lt;/li&gt;
&lt;li&gt;Amazon Redshift: Monitor &lt;code&gt;DatabaseConnections&lt;/code&gt;, &lt;code&gt;CPUUtilization&lt;/code&gt;, average &lt;code&gt;QueryDuration&lt;/code&gt;; configure alerts for active concurrency scaling clusters via the &lt;code&gt;ConcurrencyScalingActiveClusters&lt;/code&gt; metric to identify peak load frequency.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Application Log Forwarding&lt;/strong&gt;: The open &lt;code&gt;emr_common&lt;/code&gt; SDK extends standardized logging beyond DolphinScheduler’s native task logs, pushing critical lifecycle events (job start, job completion, resource consumption totals) to CloudWatch Log Streams or Amazon SNS topics for centralized analysis and automated Lambda-driven remediation workflows.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedded Data Quality Validation Checks&lt;/strong&gt;: Successful task execution exit codes do not guarantee accurate output datasets. Append dedicated Python validation tasks to the terminal stage of every DolphinScheduler workflow to run data integrity checks against Redshift tables—validating record volume thresholds, null value ratios, and business logic constraints—with immediate alert triggers for anomalous dataset quality deviations.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5.2 Field-Proven Cloud Cost Optimization Tactics
&lt;/h3&gt;

&lt;p&gt;Cloud cost governance for this integrated lakehouse architecture relies on granular workload tuning segmented by compute runtime type:&lt;/p&gt;

&lt;h4&gt;
  
  
  Cost Optimizations for EMR on EC2 Clusters
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mixed On-Demand + Spot Instance Tiering&lt;/strong&gt;: Deploy Spot Instances for all Task compute nodes to cut billing costs by 60–70%; reserve On-Demand EC2 instances for Master and Core nodes to guarantee persistent storage and cluster control plane stability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Cluster Auto-Scaling&lt;/strong&gt;: Configure YARN metric-based horizontal scaling policies responding to pending container backlogs, eliminating persistent over-provisioning of idle cluster capacity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scheduled Auto-Lifecycle Orchestration via DolphinScheduler&lt;/strong&gt;: Embed pre-workflow cluster startup and post-workflow termination Python tasks leveraging boto3 AWS SDK automation. Clusters remain provisioned exclusively during daily batch processing windows, eliminating idle-hour billing outside scheduled execution hours.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cost Optimizations for EMR Serverless Workloads
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Precision Resource Allocation Tuning&lt;/strong&gt;: Spark job driver and executor memory allocations directly determine serverless billing totals. Analyze historical CloudWatch resource utilization metrics to identify optimal memory sizing thresholds, eliminating over-provisioned reserved memory waste; standardized default tuning parameters are embedded within the shared &lt;code&gt;emr_common&lt;/code&gt; SDK.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Provisioned Capacity Warm Pools for Low-Latency Workloads&lt;/strong&gt;: Enable EMR Serverless pre-provisioned warm capacity pools for latency-sensitive micro-jobs to mitigate cold-start delay overhead. Note this feature incurs persistent background billing, requiring careful latency vs. cost tradeoff evaluation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File Compaction Pre-Processing&lt;/strong&gt;: Execute lightweight preprocessing jobs (AWS Glue ETL or S3 DistCp) to merge thousands of tiny source data files into larger optimized partitions before launching heavy EMR Serverless transformation workloads, drastically reducing job startup overhead and cumulative compute runtime spend.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Cost Optimizations for Amazon Redshift Warehouses
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Off-Peak Scheduling for Resource-Heavy Maintenance&lt;/strong&gt;: Schedule resource-intensive warehouse operations, including &lt;code&gt;VACUUM&lt;/code&gt;, full table &lt;code&gt;ANALYZE&lt;/code&gt;, and bulk INSERT/DELETE ETL loads exclusively during overnight business off-hours, avoiding resource contention with daytime BI analytical queries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dedicated WLM Query Queue Segmentation&lt;/strong&gt;: Configure separate Redshift Workload Management queues for short DolphinScheduler batch ETL jobs with isolated concurrency and memory allocations, preventing long-running complex analytical queries from starving lightweight transformation workloads.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Slow Query Monitoring &amp;amp; Tuning&lt;/strong&gt;: Track CloudWatch metrics for abnormal &lt;code&gt;QueryDuration&lt;/code&gt; and &lt;code&gt;ScanRowCount&lt;/code&gt; values, triggering automated alerts for poorly optimized queries requiring SQL refactoring or table schema adjustments (DISTKEY/SORTKEY reconfiguration).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.3 Common Production Troubleshooting Checklist
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Problem&lt;/th&gt;
&lt;th&gt;Possible Causes&lt;/th&gt;
&lt;th&gt;Troubleshooting Steps&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DolphinScheduler task remains in "Submitting" status&lt;/td&gt;
&lt;td&gt;1. Network connectivity failure between Worker nodes and AWS services.&lt;br&gt;2. The IAM role/access key does not have the corresponding permissions.&lt;br&gt;3. API calls in the encapsulated SDK time out or are blocked.&lt;/td&gt;
&lt;td&gt;1. Test connectivity using &lt;code&gt;telnet&lt;/code&gt; or &lt;code&gt;aws cli&lt;/code&gt; on the Worker nodes.&lt;br&gt;2. Check the policies attached to the IAM user used by the Worker node EC2 or DolphinScheduler.&lt;br&gt;3. View DolphinScheduler Worker logs to locate the specific error line.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EMR Serverless job submission failed&lt;/td&gt;
&lt;td&gt;1. The Application is not in the &lt;code&gt;STARTED&lt;/code&gt; state.&lt;br&gt;2. Insufficient permissions for the Execution Role.&lt;br&gt;3. The specified S3 script path does not exist or access permission is denied.&lt;/td&gt;
&lt;td&gt;1. Call the &lt;code&gt;list-applications&lt;/code&gt; API to check the status.&lt;br&gt;2. Check the policies of the Execution Role, which must have at least S3 read/write, Glue access, and CloudWatch log write permissions.&lt;br&gt;3. Manually test whether the S3 script can be read using AWS CLI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Redshift SQL task connection timeout&lt;/td&gt;
&lt;td&gt;1. The connection is blocked by the security group/network ACL.&lt;br&gt;2. The Redshift cluster is paused.&lt;br&gt;3. The number of connections is full.&lt;/td&gt;
&lt;td&gt;1. Check the inbound rules of the Redshift cluster security group.&lt;br&gt;2. Check the cluster status in the AWS console.&lt;br&gt;3. Query the &lt;code&gt;stv_sessions&lt;/code&gt; system table to check current connections.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task succeeded but data was not updated&lt;/td&gt;
&lt;td&gt;1. SQL logic error (e.g., incorrect WHERE clause).&lt;br&gt;2. Transaction not committed (some DDLs in Redshift are auto-committed, but script errors may cause subsequent DMLs to not execute).&lt;br&gt;3. Data latency (e.g., from Kinesis to S3).&lt;/td&gt;
&lt;td&gt;1. Manually run the task SQL in the Redshift query editor.&lt;br&gt;2. Check the complete SQL (after variable replacement) in the DolphinScheduler task logs.&lt;br&gt;3. Check whether the upstream data source task succeeded.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Abnormal cost surge&lt;/td&gt;
&lt;td&gt;1. The EMR cluster was not terminated on time.&lt;br&gt;2. Excessively high memory configuration for EMR Serverless jobs.&lt;br&gt;3. Redshift Concurrency Scaling is triggered excessively.&lt;/td&gt;
&lt;td&gt;1. Check the EMR cluster runtime duration alarms in CloudWatch.&lt;br&gt;2. Analyze the &lt;code&gt;MemoryUtilization&lt;/code&gt; metric of EMR Serverless jobs.&lt;br&gt;3. View the history of the &lt;code&gt;ConcurrencyScalingActiveClusters&lt;/code&gt; metric for Redshift.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqw9548fqjx8i0jm6hep.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbqw9548fqjx8i0jm6hep.jpg" width="735" height="1007"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Summary &amp;amp; Future Roadmap Outlook
&lt;/h2&gt;

&lt;p&gt;The core transformative value delivered by this integrated architecture lies in the abstraction layer introduced by Apache DolphinScheduler, unifying heterogeneous AWS compute services (EC2-backed EMR, EMR Serverless, Amazon Redshift) into a logically single, centrally governed data compute platform. Data engineers focus solely on implementing business transformation logic via SQL and PySpark, abstracted entirely from underlying cluster infrastructure management and runtime routing complexity. Platform operations teams gain a single pane of glass for full workflow visibility, standardized observability, and centralized cost governance controls.&lt;/p&gt;

&lt;p&gt;This successful deep integration rests on two foundational architectural choices: abstracted unified SDK wrapping to eliminate cross-service API disparities, plus full utilization of DolphinScheduler’s native parameterization, plugin extensibility, and built-in workload throttling controls enabling flexible, customizable orchestration policies.&lt;/p&gt;

&lt;p&gt;Looking forward to community-driven enhancements for Apache DolphinScheduler, two high-impact feature developments will further advance intelligent autonomous cloud data pipeline orchestration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SQL Syntax Tree Parsing for Column-Level Data Lineage&lt;/strong&gt;: Current lineage tracking mechanisms rely on basic regular expression matching or manual metadata entry, limiting precision. Native SQL AST parsing within DolphinScheduler task execution would generate end-to-end field-level data lineage graphs, drastically elevating enterprise data catalog and governance capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Agent Operator for Autonomous Workflow Optimization&lt;/strong&gt;: A native AI Agent task runtime would leverage historical job runtime metrics, resource consumption profiles, and input dataset volumes to dynamically auto-tune EMR Serverless executor resource allocations, intelligently route workloads between EMR runtimes, and autonomously parse failure logs to generate diagnostic troubleshooting recommendations or automated retry remediation logic. This autonomous orchestration capability represents a critical milestone toward self-operating data pipeline platforms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cloud-native data engineering is an iterative, evolving discipline; deep cross-service integration and intelligent autonomous orchestration remain core levers to boost data team engineering throughput. The standardized architectural patterns, production code samples, and hands-on troubleshooting guidance shared within this guide deliver actionable blueprints for teams building or modernizing cloud-based data scheduling platforms across global markets, including North America, Europe, India, and Southeast Asia.&lt;/p&gt;

</description>
      <category>apachedolphinscheduler</category>
      <category>aws</category>
      <category>datascience</category>
      <category>lakehouse</category>
    </item>
    <item>
      <title>Create Your First Apache DolphinScheduler Workflow in Five Minutes!</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Thu, 18 Jun 2026 07:58:22 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/create-your-first-apache-dolphinscheduler-workflow-in-five-minutes-dhc</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/create-your-first-apache-dolphinscheduler-workflow-in-five-minutes-dhc</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foc6s9e4hr6r74151xg8s.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foc6s9e4hr6r74151xg8s.jpg" width="799" height="541"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, we will use DolphinScheduler to create and run a simple workflow step by step. During this journey, you will learn the basic concepts of DolphinScheduler and know the most basic configuration to run the workflow. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Dolphinscheduler
&lt;/h2&gt;

&lt;p&gt;You have to install and start dolphinscheduler first before go ahead. For beginners, we recommend setting up DolphinScheduler with the official Docker image or with the standalone server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standalone server&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Build Your First Workflow
&lt;/h2&gt;

&lt;p&gt;You can log in DolphinScheduler through &lt;a href="http://localhost:12345/dolphinscheduler/ui" rel="noopener noreferrer"&gt;http://localhost:12345/dolphinscheduler/ui&lt;/a&gt; and the default username/password is admin/dolphinscheduler123.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fehx9gpmkage3lfg7xl36.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fehx9gpmkage3lfg7xl36.gif" alt="login" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Tenant
&lt;/h3&gt;

&lt;p&gt;Tenant is an important concept while using DolphinScheduler, so let's briefly introduce the concept of tenant first.&lt;/p&gt;

&lt;p&gt;DolphinScheduler maps the admin account you use to log into DolphinScheduler to user. To better control system resources, DolphinScheduler introduces the concept of tenants, which are used to execute tasks.&lt;/p&gt;

&lt;p&gt;The brief is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User: login web UI, do all operations in the web UI, including workflow management and tenant creation.&lt;/li&gt;
&lt;li&gt;Tenant: the actual executor of the task, A Linux user for DolphinScheduler worker.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can create a tenant in DolphinScheduler Security -&amp;gt; Tenant Manage page.&lt;/p&gt;

&lt;p&gt;NOTE: The user will bind to a default tenant when it is created, if you use the default tenant, the task will be executed by worker's bootstrap user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fue405z7hriw490tt9lfd.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fue405z7hriw490tt9lfd.gif" alt="1" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Assign Tenant to User
&lt;/h3&gt;

&lt;p&gt;As we have shown above in Create Tenant section, theuser can not run tasks until we assign it with a tenant.&lt;/p&gt;

&lt;p&gt;We can assign a tenant to a specific user in DolphinScheduler Security -&amp;gt; User Manage page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftki88v2knx0n0bfzopqi.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftki88v2knx0n0bfzopqi.gif" alt="2" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After we create a tenant and assign it to a user, we can start creating a simple workflow in DolphinScheduler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Project
&lt;/h3&gt;

&lt;p&gt;But in DolphinScheduler, all workflows must belong to a project, so we need to create a project first.&lt;/p&gt;

&lt;p&gt;We can create a project in DolphinScheduler Project page by clicking Create Project button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrrgu0tplm010zebscfw.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrrgu0tplm010zebscfw.gif" alt="3" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Workflow
&lt;/h3&gt;

&lt;p&gt;Now we can create a workflow for the project tutorial. Click the project we just created, go to Workflow Definition page, click Create Workflow button, and we will redirect to the workflow detail page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh1upx284mx8mrbq5wz96.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh1upx284mx8mrbq5wz96.gif" alt="4" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Tasks
&lt;/h3&gt;

&lt;p&gt;We can use the mouse to drag the task you want to create from the toolbar in the workflow canvas. In this case, we create a Shell task. Entering the necessary information for the task, we just fill the attribute Node Name with Script to the task for this simple workflow. After that, we can click the Save button to save the task into the workflow. We create another task using the same way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1dl5sgtsh47ainbejz3j.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F1dl5sgtsh47ainbejz3j.gif" alt="5" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Set Task Dependency
&lt;/h3&gt;

&lt;p&gt;So we have two different tasks with different names and commands to run in the workflow. The only thing missing from the current workflow is task dependency. We can add dependency using the mouse to drag the arrow from the upstream task to the downstream and then release the mouse. And you can see the link with the arrow between the two tasks is created, from the upstream task to the downstream one. Finally, we can click the Save button from the top right corner to save the workflow, do not forget to enter the name of the workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5i9lgu1cn7i27if6a8il.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F5i9lgu1cn7i27if6a8il.gif" alt="6" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Run Workflow
&lt;/h3&gt;

&lt;p&gt;After all done, we can run the workflow by clicking the Online and then the Run button from the workflows list. If you want to see the workflow instance, just go to Workflow Instance page, you can see the workflow instance is running and the status is Executing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo8eyxq79ijh5ewg2ufir.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo8eyxq79ijh5ewg2ufir.gif" alt="7" width="799" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  View Log
&lt;/h3&gt;

&lt;p&gt;If you want to view the task log, please click the workflow instance from the workflow instance list, then find the task you want to view the log, right-click the mouse and select View Log from the context dialog, and you can see the detailed log of the task.&lt;/p&gt;

&lt;p&gt;You can see the task printing Hello DolphinScheduler and Ending... which is the same as we defined when creating the tasks.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqwdaxa7gqs8g0vcq2fvk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqwdaxa7gqs8g0vcq2fvk.gif" alt="8" width="760" height="377"&gt;&lt;/a&gt;&lt;br&gt;
You just finished the first tutorial of DolphinScheduler, you can now run some simple workflows in DolphinScheduler, congratulations!&lt;/p&gt;

</description>
      <category>apachedolphinscheduler</category>
      <category>tutorial</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Deploying Apache DolphinScheduler 3.1.9 Cluster with MySQL Instead of PostgreSQL? A Practical Docker Compose Guide</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Thu, 18 Jun 2026 07:37:46 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/deploying-apache-dolphinscheduler-319-cluster-with-mysql-instead-of-postgresql-a-practical-2mam</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/deploying-apache-dolphinscheduler-319-cluster-with-mysql-instead-of-postgresql-a-practical-2mam</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F51tnl0ol1f1y5o33cnxj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F51tnl0ol1f1y5o33cnxj.png" alt="MySQL DS" width="800" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;Today, we'll walk through one of the most requested deployment scenarios in the Apache DolphinScheduler community: deploying an Apache DolphinScheduler 3.1.9 cluster with MySQL as the metadata database using Docker Compose.&lt;/p&gt;

&lt;p&gt;As many users know, the official Docker Compose deployment provided by DolphinScheduler uses PostgreSQL as the metadata repository by default. This is mainly because the GPLv2 license of MySQL is not fully compatible with Apache License 2.0, preventing the project from distributing an official MySQL-based package.&lt;/p&gt;

&lt;p&gt;However, in real-world production environments, many organizations prefer MySQL due to its mature ecosystem, extensive tooling, operational familiarity, and widespread adoption across enterprises.&lt;/p&gt;

&lt;p&gt;In this guide, we'll show how to adapt the official Docker Compose deployment and successfully run a DolphinScheduler cluster backed by MySQL metadata storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pull Required Images
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull apache/dolphinscheduler-master:3.1.9

docker pull apache/dolphinscheduler-worker:3.1.9

docker pull apache/dolphinscheduler-tools:3.1.9

docker pull apache/dolphinscheduler-api:3.1.9

docker pull apache/dolphinscheduler-alert-server:3.1.9

docker pull bitnami/zookeeper:3.7.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Download the MySQL JDBC Driver
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://downloads.mysql.com/archives/get/p/3/file/mysql-connector-j-8.0.33.zip

unzip &lt;span class="nt"&gt;-q&lt;/span&gt; mysql-connector-j-8.0.33.zip

&lt;span class="nb"&gt;cp &lt;/span&gt;mysql-connector-j-8.0.33/mysql-connector-j-8.0.33.jar &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prepare Custom Images
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dockerfile for Master, Worker, API, and Alert Server
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Based on the official DolphinScheduler image&lt;/span&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; SERVICE=api&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; apache/dolphinscheduler-${SERVICE}:3.1.9&lt;/span&gt;

&lt;span class="c"&gt;# Copy the MySQL JDBC driver into the DolphinScheduler library directory&lt;/span&gt;

&lt;span class="c"&gt;# DolphinScheduler loads JDBC drivers from the lib directory&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; mysql-connector-j-8.0.33.jar /opt/dolphinscheduler/libs/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dockerfile for Tools
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Based on the official DolphinScheduler image&lt;/span&gt;

&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; SERVICE=tools&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; apache/dolphinscheduler-${SERVICE}:3.1.9&lt;/span&gt;

&lt;span class="c"&gt;# Copy the MySQL JDBC driver into the DolphinScheduler tools library directory&lt;/span&gt;

&lt;span class="c"&gt;# DolphinScheduler loads JDBC drivers from the lib directory&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; mysql-connector-j-8.0.33.jar /opt/dolphinscheduler/tools/libs/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build Custom Images
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;SERVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;master &lt;span class="nt"&gt;-t&lt;/span&gt; apache/dolphinscheduler-master:3.1.9-mysql &lt;span class="nb"&gt;.&lt;/span&gt;

docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;SERVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;worker &lt;span class="nt"&gt;-t&lt;/span&gt; apache/dolphinscheduler-worker:3.1.9-mysql &lt;span class="nb"&gt;.&lt;/span&gt;

docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;SERVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tools &lt;span class="nt"&gt;-t&lt;/span&gt; apache/dolphinscheduler-tools:3.1.9-mysql &lt;span class="nb"&gt;.&lt;/span&gt;

docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;SERVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;api &lt;span class="nt"&gt;-t&lt;/span&gt; apache/dolphinscheduler-api:3.1.9-mysql &lt;span class="nb"&gt;.&lt;/span&gt;

docker build &lt;span class="nt"&gt;--build-arg&lt;/span&gt; &lt;span class="nv"&gt;SERVICE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;alert-server &lt;span class="nt"&gt;-t&lt;/span&gt; apache/dolphinscheduler-alert-server:3.1.9-mysql &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update docker-compose.yaml
&lt;/h2&gt;

&lt;p&gt;Disable the PostgreSQL service and add a MySQL service as the metadata database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Comment out the PostgreSQL service&lt;/span&gt;

&lt;span class="c1"&gt;# dolphinscheduler-postgresql:&lt;/span&gt;
&lt;span class="c1"&gt;#   image: bitnami/postgresql:15.2.0&lt;/span&gt;
&lt;span class="c1"&gt;#   ...&lt;/span&gt;

&lt;span class="c1"&gt;# MySQL Metadata Database Service&lt;/span&gt;

&lt;span class="na"&gt;dolphinscheduler-mysql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysql:8.0&lt;/span&gt;
  &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dolphinscheduler-mysql&lt;/span&gt;

  &lt;span class="na"&gt;profiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;schema&lt;/span&gt;

  &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MYSQL_ROOT_PASSWORD:-root}&lt;/span&gt;
    &lt;span class="na"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${MYSQL_DATABASE:-dolphinscheduler}&lt;/span&gt;

  &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dolphinscheduler-mysql:/var/lib/mysql&lt;/span&gt;

  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3306:3306"&lt;/span&gt;

  &lt;span class="c1"&gt;# Expose MySQL to allow workers on other servers to connect&lt;/span&gt;

  &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;[&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mysqladmin"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ping"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-h"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;localhost"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-u"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${MYSQL_USERNAME:-root}"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-p${MYSQL_PASSWORD:-root}"&lt;/span&gt;
      &lt;span class="pi"&gt;]&lt;/span&gt;

    &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;60s&lt;/span&gt;
    &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;120&lt;/span&gt;

  &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dolphinscheduler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The remaining services (ZooKeeper, Schema Initializer, API, Alert Server, Master, Worker, Network, and Volume configurations) remain the same as the official Docker Compose deployment, with the following key modifications:&lt;/p&gt;

&lt;h3&gt;
  
  
  Schema Initializer Dependency
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dolphinscheduler-mysql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Master JVM Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;JAVA_OPTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;-server&lt;/span&gt;
    &lt;span class="s"&gt;-Duser.timezone=${SPRING_JACKSON_TIME_ZONE}&lt;/span&gt;
    &lt;span class="s"&gt;-Xms8g&lt;/span&gt;
    &lt;span class="s"&gt;-Xmx8g&lt;/span&gt;
    &lt;span class="s"&gt;-Xmn4g&lt;/span&gt;
    &lt;span class="s"&gt;-XX:+PrintGCDetails&lt;/span&gt;
    &lt;span class="s"&gt;-Xloggc:gc.log&lt;/span&gt;
    &lt;span class="s"&gt;-XX:+HeapDumpOnOutOfMemoryError&lt;/span&gt;
    &lt;span class="s"&gt;-XX:HeapDumpPath=dump.hprof&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Worker JVM Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;JAVA_OPTS&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="s"&gt;-server&lt;/span&gt;
    &lt;span class="s"&gt;-Duser.timezone=${SPRING_JACKSON_TIME_ZONE}&lt;/span&gt;
    &lt;span class="s"&gt;-Xms8g&lt;/span&gt;
    &lt;span class="s"&gt;-Xmx8g&lt;/span&gt;
    &lt;span class="s"&gt;-Xmn4g&lt;/span&gt;
    &lt;span class="s"&gt;-XX:+PrintGCDetails&lt;/span&gt;
    &lt;span class="s"&gt;-Xloggc:gc.log&lt;/span&gt;
    &lt;span class="s"&gt;-XX:+HeapDumpOnOutOfMemoryError&lt;/span&gt;
    &lt;span class="s"&gt;-XX:HeapDumpPath=dump.hprof&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Volume Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Comment out PostgreSQL volume&lt;/span&gt;

  &lt;span class="c1"&gt;# dolphinscheduler-postgresql:&lt;/span&gt;

  &lt;span class="na"&gt;dolphinscheduler-mysql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dolphinscheduler-zookeeper&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dolphinscheduler-worker-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dolphinscheduler-logs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;dolphinscheduler-shared-local&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update the .env File
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="c"&gt;# Docker Hub Repository and Image Tag
&lt;/span&gt;
&lt;span class="py"&gt;HUB&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;apache&lt;/span&gt;
&lt;span class="py"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;3.1.9&lt;/span&gt;

&lt;span class="c"&gt;# MySQL Configuration
&lt;/span&gt;
&lt;span class="py"&gt;MYSQL_ROOT_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;root&lt;/span&gt;
&lt;span class="py"&gt;MYSQL_DATABASE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;dolphinscheduler&lt;/span&gt;
&lt;span class="py"&gt;MYSQL_USERNAME&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;root&lt;/span&gt;
&lt;span class="py"&gt;MYSQL_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;root&lt;/span&gt;

&lt;span class="c"&gt;# DolphinScheduler Database Configuration
&lt;/span&gt;
&lt;span class="py"&gt;TZ&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Asia/Shanghai&lt;/span&gt;

&lt;span class="c"&gt;# Use MySQL as the metadata database
&lt;/span&gt;
&lt;span class="py"&gt;DATABASE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;mysql&lt;/span&gt;

&lt;span class="py"&gt;SPRING_JACKSON_TIME_ZONE&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;GMT+8&lt;/span&gt;

&lt;span class="py"&gt;SPRING_DATASOURCE_URL&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;jdbc:mysql://dolphinscheduler-mysql:3306/${MYSQL_DATABASE}?useUnicode=true&amp;amp;characterEncoding=UTF-8&amp;amp;useSSL=false&amp;amp;serverTimezone=Asia/Shanghai&amp;amp;allowPublicKeyRetrieval=true&lt;/span&gt;

&lt;span class="py"&gt;SPRING_DATASOURCE_USERNAME&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${MYSQL_USERNAME}&lt;/span&gt;

&lt;span class="py"&gt;SPRING_DATASOURCE_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;${MYSQL_PASSWORD}&lt;/span&gt;

&lt;span class="py"&gt;REGISTRY_ZOOKEEPER_CONNECT_STRING&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;dolphinscheduler-zookeeper:2181&lt;/span&gt;

&lt;span class="py"&gt;MASTER_FETCH_COMMAND_NUM&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Initialize the Database
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;--profile&lt;/span&gt; schema up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start the Entire Cluster
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;--profile&lt;/span&gt; all up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start the Worker Service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; dolphinscheduler-worker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start the Master Service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; dolphinscheduler-master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start the Alert Service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; dolphinscheduler-alert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start the API Service
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt; dolphinscheduler-api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Restart All Services
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose &lt;span class="nt"&gt;--profile&lt;/span&gt; all restart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Although Apache DolphinScheduler officially ships with a PostgreSQL-based Docker Compose deployment, many enterprises continue to standardize on MySQL for operational consistency and ecosystem compatibility.&lt;/p&gt;

&lt;p&gt;By adding the MySQL JDBC driver, rebuilding the DolphinScheduler images, and adjusting the Docker Compose and environment configurations, you can quickly deploy a fully functional Apache DolphinScheduler 3.1.9 cluster powered by MySQL metadata storage.&lt;/p&gt;

&lt;p&gt;This approach enables teams already invested in the MySQL ecosystem to integrate DolphinScheduler into their infrastructure with minimal friction while preserving the benefits of containerized deployment and cluster-based scheduling.&lt;/p&gt;

&lt;p&gt;If your organization relies on MySQL as a strategic database platform, this solution provides a practical and production-friendly path to running Apache DolphinScheduler at scale.&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>apachedolphinscheduler</category>
      <category>doris</category>
      <category>postgressql</category>
    </item>
    <item>
      <title>Hands-On Demo: Incremental MySQL-to-Doris Synchronization with Apache DolphinScheduler and Apache SeaTunnel</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Thu, 11 Jun 2026 03:48:39 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/hands-on-demo-incremental-mysql-to-doris-synchronization-with-apache-dolphinscheduler-and-apache-40mg</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/hands-on-demo-incremental-mysql-to-doris-synchronization-with-apache-dolphinscheduler-and-apache-40mg</guid>
      <description>&lt;p&gt;Data synchronization is one of the most common requirements in enterprise data platform development. As business volume continues to grow, full data synchronization can place increasing pressure on source databases while consuming substantial computing and storage resources. As a result, incremental synchronization has become the preferred approach in most production environments.&lt;/p&gt;

&lt;p&gt;In this demo, we will combine Apache DolphinScheduler and Apache SeaTunnel to implement a typical offline incremental synchronization scenario. DolphinScheduler retrieves the synchronization checkpoint from the target system and passes it to SeaTunnel as a runtime parameter, enabling incremental data synchronization from MySQL to Apache Doris.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tzz4foestm5zcd4ndw1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7tzz4foestm5zcd4ndw1.jpg" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is based on an actual demonstration and provides a complete walkthrough of the environment setup, SeaTunnel configuration, and DolphinScheduler workflow configuration process.&lt;/p&gt;

&lt;p&gt;For the full demo, please refer to:&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/ObUaVOuoDC8"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Environment Setup
&lt;/h1&gt;

&lt;p&gt;This demonstration uses the following components:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Apache SeaTunnel&lt;/td&gt;
&lt;td&gt;2.3.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apache DolphinScheduler&lt;/td&gt;
&lt;td&gt;3.x&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;8.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apache Doris&lt;/td&gt;
&lt;td&gt;2.x&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;In this architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MySQL serves as the source database.&lt;/li&gt;
&lt;li&gt;Doris serves as the target database.&lt;/li&gt;
&lt;li&gt;SeaTunnel is responsible for data synchronization.&lt;/li&gt;
&lt;li&gt;DolphinScheduler handles workflow orchestration and scheduling.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  2. Preparing Test Data
&lt;/h1&gt;

&lt;p&gt;Before configuring the synchronization task, we first prepare sample business data.&lt;/p&gt;

&lt;p&gt;In this demonstration, a database named shopping is used as the sample database, and an orders table is created.&lt;/p&gt;

&lt;p&gt;The orders table contains an auto-incrementing primary key column:&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="n"&gt;order_id&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This field will later be used as the incremental synchronization checkpoint.&lt;/p&gt;

&lt;p&gt;To verify synchronization results, a batch of sample records is inserted into the table. Approximately 300 order records are generated using a script.&lt;/p&gt;

&lt;p&gt;The following information is then inspected:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current total number of orders&lt;/li&gt;
&lt;li&gt;Current maximum order ID&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These values will serve as references when configuring incremental synchronization logic later.&lt;/p&gt;

&lt;p&gt;It is worth noting that order_id is used only for demonstration purposes. In real-world production scenarios, timestamp fields such as update_time or create_time are often used as incremental synchronization conditions.&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Incremental Synchronization Design
&lt;/h1&gt;

&lt;p&gt;Before configuring SeaTunnel, let's first understand the overall synchronization strategy.&lt;/p&gt;

&lt;p&gt;The core idea is to use data that has already been synchronized into Doris to determine the current synchronization progress.&lt;/p&gt;

&lt;p&gt;The workflow operates as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Query the current maximum order ID in Doris.&lt;/li&gt;
&lt;li&gt;Use this value as the synchronization checkpoint.&lt;/li&gt;
&lt;li&gt;SeaTunnel reads records from MySQL whose order IDs are greater than this checkpoint.&lt;/li&gt;
&lt;li&gt;Newly added records are written into Doris.&lt;/li&gt;
&lt;li&gt;During the next execution, synchronization resumes from the latest checkpoint.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, if the current maximum order ID in Doris is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;300
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SeaTunnel will execute the following condition:&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;WHERE&lt;/span&gt; &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that only newly inserted records are processed during each run, preventing duplicate synchronization of existing data.&lt;/p&gt;

&lt;p&gt;As emphasized during the demonstration, the incremental field does not necessarily have to be a primary key. Any field that can accurately identify newly added or modified data can be used.&lt;/p&gt;

&lt;h1&gt;
  
  
  4. Configuring the SeaTunnel Job
&lt;/h1&gt;

&lt;p&gt;After defining the synchronization strategy, we can start configuring the SeaTunnel job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the JDBC Source
&lt;/h2&gt;

&lt;p&gt;Since the source data resides in MySQL, JDBC Source is used to read the data.&lt;/p&gt;

&lt;p&gt;The core query is:&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="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;order_id&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important part is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${order_id}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This value is not hardcoded. Instead, it will be dynamically supplied by DolphinScheduler.&lt;/p&gt;

&lt;p&gt;When the workflow runs, SeaTunnel automatically replaces this variable with the actual synchronization checkpoint, enabling incremental extraction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Parallelism
&lt;/h2&gt;

&lt;p&gt;The demonstration also configures task parallelism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hocon"&gt;&lt;code&gt;&lt;span class="nl"&gt;parallelism&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Increasing parallelism can significantly improve synchronization performance.&lt;/p&gt;

&lt;p&gt;In production environments, the appropriate value should be determined based on available server resources and database workload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Partitioned Reads
&lt;/h2&gt;

&lt;p&gt;To improve performance when reading large tables, partitioned reading is also introduced.&lt;/p&gt;

&lt;p&gt;The partition column is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;order_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hocon"&gt;&lt;code&gt;&lt;span class="nl"&gt;partition_column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"order_id"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Combined with the partition_num parameter, the dataset is divided into multiple partitions that can be processed in parallel.&lt;/p&gt;

&lt;p&gt;This approach can greatly improve synchronization efficiency for large-scale datasets.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Fetch Size
&lt;/h2&gt;

&lt;p&gt;Within the JDBC Connector, fetch_size can be used to control the number of records retrieved from the database per fetch operation.&lt;/p&gt;

&lt;p&gt;Proper configuration of this parameter can reduce database round trips and improve overall read performance.&lt;/p&gt;

&lt;h1&gt;
  
  
  5. Configuring the Doris Sink
&lt;/h1&gt;

&lt;p&gt;After completing the Source configuration, the next step is configuring the Doris Sink.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automatic Table Creation
&lt;/h2&gt;

&lt;p&gt;The demonstration first introduces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hocon"&gt;&lt;code&gt;&lt;span class="l"&gt;create_schema&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This parameter enables automatic creation of target tables.&lt;/p&gt;

&lt;p&gt;By leveraging automatic table creation, users can significantly reduce the effort required to manually maintain Doris table schemas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Write Mode
&lt;/h2&gt;

&lt;p&gt;Since this example uses incremental synchronization, append mode is selected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hocon"&gt;&lt;code&gt;&lt;span class="nl"&gt;save_mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;APPEND_DATA&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;APPEND_DATA is used because each synchronization run only processes newly added records and does not need to overwrite historical data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Two-Phase Commit
&lt;/h2&gt;

&lt;p&gt;To ensure data consistency, the demonstration also introduces:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hocon"&gt;&lt;code&gt;&lt;span class="nl"&gt;enable_2pc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enabling this option activates the two-phase commit mechanism, providing more reliable data writes.&lt;/p&gt;

&lt;p&gt;It also helps guarantee Exactly-Once semantics during data synchronization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance Optimization Parameters
&lt;/h2&gt;

&lt;p&gt;Several performance-related parameters are also discussed, including:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hocon"&gt;&lt;code&gt;&lt;span class="l"&gt;batch_size&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hocon"&gt;&lt;code&gt;&lt;span class="l"&gt;buffer_size&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These parameters primarily control batch write behavior and can significantly improve Doris ingestion performance.&lt;/p&gt;

&lt;h1&gt;
  
  
  6. Configuring the DolphinScheduler Runtime Environment
&lt;/h1&gt;

&lt;p&gt;After completing the SeaTunnel configuration, the next step is setting up DolphinScheduler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Tenant
&lt;/h2&gt;

&lt;p&gt;First, navigate to the &lt;strong&gt;Security Center&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Open the Tenant Management page and create a new tenant.&lt;/p&gt;

&lt;p&gt;The demonstration specifically emphasizes that all tasks in DolphinScheduler are ultimately executed under a tenant identity. Therefore, tenant configuration is an essential step in preparing the runtime environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a User and Associate It with the Tenant
&lt;/h2&gt;

&lt;p&gt;Next, navigate to the User Management page.&lt;/p&gt;

&lt;p&gt;Create a user and associate it with the tenant created in the previous step.&lt;/p&gt;

&lt;p&gt;Once configured, the user will have permission to execute tasks under the corresponding tenant.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an Environment
&lt;/h2&gt;

&lt;p&gt;Next, open the Environment Management page.&lt;/p&gt;

&lt;p&gt;Create a runtime environment for SeaTunnel.&lt;/p&gt;

&lt;p&gt;Configure the following environment variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SEATUNNEL_HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/soft/seatunnel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration tells DolphinScheduler where SeaTunnel is installed.&lt;/p&gt;

&lt;p&gt;When a workflow executes a SeaTunnel task, DolphinScheduler uses this path to locate the corresponding execution scripts.&lt;/p&gt;

&lt;p&gt;The demonstration highlights that this configuration is mandatory and should not be skipped.&lt;/p&gt;

&lt;h1&gt;
  
  
  7. Creating the Project and Workflow
&lt;/h1&gt;

&lt;p&gt;After completing the environment setup, create a new project.&lt;/p&gt;

&lt;p&gt;In this demonstration, a project named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;shopping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is created.&lt;/p&gt;

&lt;p&gt;After entering the project, create a new workflow.&lt;/p&gt;

&lt;p&gt;The workflow contains two core nodes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;SQL Task&lt;/li&gt;
&lt;li&gt;SeaTunnel Task&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The SQL Task is responsible for retrieving the synchronization checkpoint, while the SeaTunnel Task performs the actual data synchronization.&lt;/p&gt;

&lt;h1&gt;
  
  
  8. Configuring the SQL Task to Retrieve the Synchronization Checkpoint
&lt;/h1&gt;

&lt;p&gt;This is the most critical step in the entire solution.&lt;/p&gt;

&lt;p&gt;First, create an SQL Task and select the Doris datasource.&lt;/p&gt;

&lt;p&gt;The purpose of this task is to determine how far synchronization has progressed by querying the latest synchronized order ID.&lt;/p&gt;

&lt;p&gt;The SQL statement is:&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;IFNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;order_id&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The demonstration specifically explains why the following statement should not be used directly:&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="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&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;orders&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reason is that during the initial synchronization, the Doris table may still be empty.&lt;/p&gt;

&lt;p&gt;In this case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MAX(order_id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NULL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If NULL is passed directly to the downstream SeaTunnel task, it may generate an invalid query condition.&lt;/p&gt;

&lt;p&gt;Therefore:&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="n"&gt;IFNULL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;MAX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is used to convert NULL values into 0.&lt;/p&gt;

&lt;p&gt;This ensures that the initial synchronization starts correctly from the very first record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure an OUT Parameter
&lt;/h2&gt;

&lt;p&gt;The query result must be passed to downstream tasks.&lt;/p&gt;

&lt;p&gt;To accomplish this, create a custom parameter within the SQL Task.&lt;/p&gt;

&lt;p&gt;Select the parameter type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OUT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the parameter name to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;order_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SQL query result will then be stored as a workflow variable.&lt;/p&gt;

&lt;p&gt;The SeaTunnel task can subsequently reference this variable directly.&lt;/p&gt;

&lt;h1&gt;
  
  
  9. Incremental Synchronization Workflow Logic
&lt;/h1&gt;

&lt;p&gt;Once the SQL Task is configured, the entire incremental synchronization pipeline is established.&lt;/p&gt;

&lt;p&gt;When the workflow runs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The SQL Task queries the current maximum order_id in Doris.&lt;/li&gt;
&lt;li&gt;The result is stored as a workflow variable.&lt;/li&gt;
&lt;li&gt;SeaTunnel uses &lt;code&gt;${order_id}&lt;/code&gt; as the query condition.&lt;/li&gt;
&lt;li&gt;Newly added records are extracted from MySQL.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Through this approach, offline incremental synchronization based on a business primary key can be implemented efficiently and reliably.&lt;/p&gt;

&lt;h1&gt;
  
  
  10. Conclusion
&lt;/h1&gt;

&lt;p&gt;This example demonstrates how to implement offline incremental synchronization by combining Apache DolphinScheduler and Apache SeaTunnel.&lt;/p&gt;

&lt;p&gt;SeaTunnel handles data extraction and loading, while DolphinScheduler manages synchronization checkpoint retrieval, parameter passing, workflow orchestration, and scheduling.&lt;/p&gt;

&lt;p&gt;The key idea behind this solution is querying the maximum order_id from the target Doris table through an SQL Task and passing the result to SeaTunnel through an OUT parameter. SeaTunnel then uses the checkpoint to perform incremental extraction from MySQL.&lt;/p&gt;

&lt;p&gt;For data warehouse construction, ODS synchronization, and recurring offline synchronization scenarios, this solution offers several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple implementation&lt;/li&gt;
&lt;li&gt;Easy maintenance&lt;/li&gt;
&lt;li&gt;Strong extensibility&lt;/li&gt;
&lt;li&gt;Production-ready incremental synchronization capabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, it provides a practical and highly valuable reference architecture for enterprise data platform development.&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>apachedolphinscheduler</category>
      <category>apacheseatunnel</category>
      <category>doris</category>
    </item>
    <item>
      <title>Apache DolphinScheduler 3.4.2 Released! Introducing Amazon EMR Serverless Support, Enhanced Monitoring, and Improved Backfill Capabilities</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Thu, 11 Jun 2026 03:45:35 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/apache-dolphinscheduler-342-released-introducing-amazon-emr-serverless-support-enhanced-55no</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/apache-dolphinscheduler-342-released-introducing-amazon-emr-serverless-support-enhanced-55no</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ix0f5ohojy2kzu6dbj6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0ix0f5ohojy2kzu6dbj6.jpg" width="799" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Apache DolphinScheduler community has officially announced the release of &lt;strong&gt;Apache DolphinScheduler 3.4.2&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As an important maintenance release in the 3.4.x series, version 3.4.2 continues the community’s tradition of delivering high-quality iterations. This release introduces several user-facing enhancements, including the new Amazon EMR Serverless Task Plugin and improvements to the Monitoring Center. It also delivers extensive optimizations and refactoring across complement data processing, task plugin capabilities, security governance, permission control, and the underlying architecture.&lt;/p&gt;

&lt;p&gt;From a release perspective, DolphinScheduler 3.4.2 includes more than one hundred merged pull requests covering feature enhancements, stability fixes, code governance, documentation improvements, and CI/CD optimizations. Contributors from across the global community participated in this release, further advancing DolphinScheduler as an enterprise-grade cloud-native workflow orchestration platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon EMR Serverless Officially Joins the DolphinScheduler Ecosystem
&lt;/h2&gt;

&lt;p&gt;As more organizations deploy data platforms on AWS, serverless architectures are becoming an increasingly important direction for big data computing.&lt;/p&gt;

&lt;p&gt;To address this demand, the community introduced the Amazon EMR Serverless Task Plugin in this release (PR #18069, contributed by @norrishuang).&lt;/p&gt;

&lt;p&gt;With this plugin, users can directly submit and manage Amazon EMR Serverless jobs from within DolphinScheduler, enabling unified orchestration and scheduling of Spark and other big data workloads without maintaining the underlying compute clusters. For data lakes, offline data warehouses, and AI-driven data processing scenarios, this translates into lower operational costs and higher resource utilization.&lt;/p&gt;

&lt;p&gt;The addition of this capability further expands DolphinScheduler’s coverage within the AWS cloud-native ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhanced Monitoring Center Delivers Greater Operational Visibility
&lt;/h2&gt;

&lt;p&gt;In production environments, one of the most common questions for operations teams is understanding which workflows and tasks are currently running.&lt;/p&gt;

&lt;p&gt;Previously, troubleshooting often required logging into servers and manually inspecting logs or process information. To improve this experience, the community enhanced the Monitoring Center through PR #18138 (contributed by @ruanwenjun).&lt;/p&gt;

&lt;p&gt;After the upgrade, users can directly view workflows currently being executed by Active Masters and tasks currently running on Active Workers from the Monitoring UI. This provides a much clearer view of cluster activity and significantly improves troubleshooting efficiency.&lt;/p&gt;

&lt;p&gt;For large-scale deployments, this enhancement further strengthens DolphinScheduler’s observability capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complement Data Capabilities Further Improved
&lt;/h2&gt;

&lt;p&gt;Complement Data (backfill processing) remains a core capability for offline data warehouses and modern data platforms.&lt;/p&gt;

&lt;p&gt;In previous releases, dependency handling in certain backfill scenarios still had limitations. To address this issue, the community completed the implementation related to DSIP-95.&lt;/p&gt;

&lt;p&gt;PR #18003, contributed by @det101, improves dependency task handling in complement data scenarios. After the upgrade, the system can correctly identify and calculate dependencies during historical data backfill operations, ensuring both accuracy and completeness throughout the backfill process.&lt;/p&gt;

&lt;p&gt;This enhancement is particularly valuable for T+1 data warehouses, historical data recomputation, and offline metric correction scenarios.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continued Enhancements to SQL, Flink, and Other Task Plugins
&lt;/h2&gt;

&lt;p&gt;Task plugins continue to be one of the most actively evolving areas of DolphinScheduler.&lt;/p&gt;

&lt;p&gt;For SQL Tasks, PR #18020 (contributed by @macdoor) introduces support for loading SQL statements directly from resource files while also supporting parameter placeholder substitution.&lt;/p&gt;

&lt;p&gt;This enhancement allows complex SQL logic to be maintained in Resource Center files rather than embedded directly within task definitions. As a result, organizations can manage SQL assets more systematically while simplifying version control and collaborative development.&lt;/p&gt;

&lt;p&gt;Within the Flink ecosystem, PR #17987 (also contributed by @macdoor) adds parameter substitution support to both Flink Task and FlinkStream Task plugins.&lt;/p&gt;

&lt;p&gt;With this capability, users can dynamically generate task parameters at runtime, enabling workflows to adapt more easily to different environments and business scenarios. For organizations that manage multi-tenant configurations, dynamic date calculations, or environment switching, this feature significantly improves orchestration flexibility and operational efficiency.&lt;/p&gt;

&lt;p&gt;In addition, the community further improved configuration flexibility for Flink tasks. PR #17909 (contributed by @leocook) exposes the Flink &lt;strong&gt;-sae&lt;/strong&gt; parameter in the Web UI and sets its default value to disabled.&lt;/p&gt;

&lt;p&gt;Through graphical configuration, users can control relevant runtime parameters without modifying underlying configuration files, further lowering the barrier to adopting Flink tasks within DolphinScheduler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Improvements in Security and Permission Governance
&lt;/h2&gt;

&lt;p&gt;Enterprise-grade scheduling platforms require robust security governance.&lt;/p&gt;

&lt;p&gt;In this release, the community completed implementation work related to DSIP-37. PR #18119, contributed by @SbloodyS, introduces the ability to disable Jetty HTTP TRACE requests through configuration.&lt;/p&gt;

&lt;p&gt;TRACE requests are rarely used in business scenarios but can potentially be exploited for information discovery. Disabling this capability helps reduce potential security risks and further strengthens system security.&lt;/p&gt;

&lt;p&gt;Regarding datasource access control, PR #18073 (contributed by @njnu-seafish) introduces permission validation mechanisms for interfaces including connectionTest, getDatabases, getTables, and getTableColumns.&lt;/p&gt;

&lt;p&gt;After the upgrade, unauthorized users can no longer retrieve related metadata information, further reinforcing security boundaries around data access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Optimization and Refactoring
&lt;/h2&gt;

&lt;p&gt;While new features are often the most visible improvements for users, consistent code standards, architectural refinements, and logic optimization are equally critical to the long-term sustainability of an open-source project.&lt;/p&gt;

&lt;p&gt;In this release, the community continued optimizing and refactoring several core modules, including API, DAO, Datasource, Alert, Worker, and Storage. These improvements standardized implementation patterns, removed redundant logic, and further enhanced the maintainability and extensibility of the system.&lt;/p&gt;

&lt;p&gt;Related pull requests include:&lt;/p&gt;

&lt;p&gt;PR18103, PR18104, PR18105, PR18107, PR18111, PR18112, PR18113, PR18114, PR18115, PR18116, PR18117, and PR18118.&lt;/p&gt;

&lt;p&gt;Meanwhile, @ruanwenjun continued advancing the Repository DAO refactoring initiative and the optimization of return object types.&lt;/p&gt;

&lt;p&gt;Related pull requests include:&lt;/p&gt;

&lt;p&gt;PR18226, PR18227, PR18228, PR18229, PR18230, PR18232, PR18233, PR18234, PR18236, PR18245, as well as multiple Repository refactoring pull requests from PR18250 through PR18263.&lt;/p&gt;

&lt;p&gt;These improvements replace a large number of Map-based return structures with strongly typed objects, establishing a cleaner architectural foundation for future development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improved Stability Through Numerous Critical Fixes
&lt;/h2&gt;

&lt;p&gt;In addition to feature enhancements, DolphinScheduler 3.4.2 resolves multiple critical issues encountered in production environments.&lt;/p&gt;

&lt;p&gt;PR #18033 (contributed by @ruanwenjun) improves JDBC connection creation by switching to a Driver-based approach, resulting in more reliable database connectivity.&lt;/p&gt;

&lt;p&gt;PR #18042 and PR #18044 (contributed by @njnu-seafish) fix parameter passing issues affecting Kubernetes Task and Zeppelin Task plugins.&lt;/p&gt;

&lt;p&gt;PR #18155 (contributed by @SbloodyS) resolves an issue where date parameters were incorrectly propagated to sub-workflows during complement data execution.&lt;/p&gt;

&lt;p&gt;PR #18146 (contributed by @SbloodyS) fixes a problem that could cause workflows using the CONTINUE strategy to remain in the RUNNING state indefinitely.&lt;/p&gt;

&lt;p&gt;PR #18183 (contributed by @ruanwenjun) addresses a permission vulnerability that allowed users to delete task definitions from unauthorized projects.&lt;/p&gt;

&lt;p&gt;PR #18212 and PR #18300 (contributed by @ruanwenjun) further strengthen permission validation for Workflow Trigger and Access Token-related operations.&lt;/p&gt;

&lt;p&gt;In addition, the community resolved several other stability-related issues, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Compose deployment exceptions&lt;/li&gt;
&lt;li&gt;Helm Chart configuration problems&lt;/li&gt;
&lt;li&gt;JDBC Registry REMOVE event anomalies&lt;/li&gt;
&lt;li&gt;SQL License Header parsing issues&lt;/li&gt;
&lt;li&gt;Multiple defects affecting deployment reliability and runtime stability&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these fixes significantly improve the robustness of DolphinScheduler in enterprise production environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continued Improvements to Documentation and Engineering Infrastructure
&lt;/h2&gt;

&lt;p&gt;Beyond code-level enhancements, the community continues investing heavily in documentation and engineering excellence.&lt;/p&gt;

&lt;p&gt;This release updates the FAQ documentation, improves parameter passing explanations, introduces AGENT.md and CLAUDE.md files, and fixes multiple documentation formatting and broken-link issues.&lt;/p&gt;

&lt;p&gt;On the CI/CD front, the community restored Python end-to-end testing, improved unit test execution efficiency, optimized the Docker release process, and enhanced GitHub Code Owner management mechanisms.&lt;/p&gt;

&lt;p&gt;Although these improvements may not appear directly in product feature lists, they serve as essential infrastructure that supports the long-term health and sustainability of the project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks to All Contributors
&lt;/h2&gt;

&lt;p&gt;The successful release of Apache DolphinScheduler 3.4.2 would not have been possible without the collective efforts of contributors from around the world.&lt;/p&gt;

&lt;p&gt;Special thanks go to Release Manager @ruanwenjun for his outstanding leadership and coordination throughout the release cycle.&lt;/p&gt;

&lt;p&gt;Under his guidance, a total of 19 contributors successfully delivered this release:&lt;/p&gt;

&lt;p&gt;@ruanwenjun&lt;/p&gt;

&lt;p&gt;@SbloodyS&lt;/p&gt;

&lt;p&gt;@det101&lt;/p&gt;

&lt;p&gt;@njnu-seafish&lt;/p&gt;

&lt;p&gt;@macdoor&lt;/p&gt;

&lt;p&gt;@norrishuang&lt;/p&gt;

&lt;p&gt;@leocook&lt;/p&gt;

&lt;p&gt;@wcmolin&lt;/p&gt;

&lt;p&gt;@asadjan4611&lt;/p&gt;

&lt;p&gt;@HEEKDragonOne&lt;/p&gt;

&lt;p&gt;@CloudExtreme&lt;/p&gt;

&lt;p&gt;@Mrhs121&lt;/p&gt;

&lt;p&gt;@hiSandog&lt;/p&gt;

&lt;p&gt;@pjfanning&lt;/p&gt;

&lt;p&gt;@sanjana2505006&lt;/p&gt;

&lt;p&gt;@shaolei7788&lt;/p&gt;

&lt;p&gt;@llphxd&lt;/p&gt;

&lt;p&gt;@includetts&lt;/p&gt;

&lt;p&gt;@shrihari7396&lt;/p&gt;

&lt;p&gt;We would also like to thank everyone who contributed code, submitted issues, improved documentation, or provided valuable community feedback.&lt;/p&gt;

&lt;p&gt;It is the continued dedication of every contributor that enables Apache DolphinScheduler to keep evolving and moving forward.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download and Upgrade
&lt;/h2&gt;

&lt;p&gt;Apache DolphinScheduler 3.4.2 is now officially available.&lt;/p&gt;

&lt;p&gt;This release delivers substantial improvements across cloud-native capabilities, monitoring and observability, security governance, task plugins, and overall system stability. It provides a more reliable, efficient, and secure workflow orchestration experience for enterprise production environments.&lt;/p&gt;

&lt;p&gt;We encourage all users to upgrade and explore the latest enhancements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Download:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://dolphinscheduler.apache.org/zh-cn/download/3.4.2" rel="noopener noreferrer"&gt;https://dolphinscheduler.apache.org/zh-cn/download/3.4.2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Release Notes:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/apache/dolphinscheduler/releases/tag/3.4.2" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/releases/tag/3.4.2&lt;/a&gt;&lt;/p&gt;

</description>
      <category>apachedolphinschduler</category>
      <category>aws</category>
      <category>emr</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Inside DolphinScheduler’s May 2026 Release: Better Failover, Stronger Security, and More Reliable Plugins</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Fri, 05 Jun 2026 10:07:17 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/inside-dolphinschedulers-may-2026-release-better-failover-stronger-security-and-more-reliable-5b9e</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/inside-dolphinschedulers-may-2026-release-better-failover-stronger-security-and-more-reliable-5b9e</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj1aylxkx7ojk731uc4f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftj1aylxkx7ojk731uc4f.jpg" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The May 2026 DolphinScheduler community update can be summarized with two keywords: &lt;strong&gt;stability&lt;/strong&gt; and &lt;strong&gt;precision&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;On one hand, major stability risks such as Master failover issues—which can have a significant impact on production environments when failures occur—have been addressed. On the other hand, long-standing usability problems, including API authorization gaps, plugin dependency conflicts, and RemoteShell null pointer exceptions, have been systematically fixed.&lt;/p&gt;

&lt;p&gt;This monthly report highlights the key changes merged into the &lt;code&gt;dev&lt;/code&gt; branch during May, including their impact on users, whether upgrades should be considered, and how to validate them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monthly Statistics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Merged PRs: &lt;strong&gt;50&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Contributors: &lt;strong&gt;7&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Code Changes: &lt;strong&gt;+10,036 / -8,542&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Major Modules Involved: API, DAO, Master, Task Plugin, CI/Testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You will notice that testing-related changes account for a large proportion of the updates. This reflects the community's effort to build a stronger foundation for future iterations. Stable and efficient CI/UT pipelines enable faster feature delivery and more reliable bug fixes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Should Read This?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;End users and business teams: Want to know which common issues were fixed and whether production environments will become more stable.&lt;/li&gt;
&lt;li&gt;Operations and platform engineers: Care about failover, permissions, logging, and plugin stability.&lt;/li&gt;
&lt;li&gt;Developers: Want a quick overview of recent engineering governance efforts, including CI, unit testing, and quality assurance improvements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The 6 Improvements Users Will Notice Most
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. More Reliable Master Failover
&lt;/h3&gt;

&lt;p&gt;Typical scenario: after a Master node crashes, cluster recovery is slow or failover becomes stuck.&lt;/p&gt;

&lt;p&gt;One of May's major fixes addresses failover lock leaks, reducing the likelihood that the scheduler remains unavailable for an extended period after failures.&lt;/p&gt;

&lt;p&gt;Related PR:&lt;br&gt;
&lt;a href="https://github.com/apache/dolphinscheduler/pull/18207" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18207&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. More Rigorous Authorization for Critical APIs
&lt;/h3&gt;

&lt;p&gt;Project-level authorization checks have been added to APIs such as view-gantt, view-variables, and trigger workflow.&lt;/p&gt;

&lt;p&gt;This makes the permission model more intuitive: users without proper authorization should not be able to access these resources.&lt;/p&gt;

&lt;p&gt;Related PR:&lt;br&gt;
&lt;a href="https://github.com/apache/dolphinscheduler/pull/18212" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18212&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Fewer Null Pointer Exceptions in RemoteShell Tasks
&lt;/h3&gt;

&lt;p&gt;Null pointer exceptions in remote tasks are notoriously difficult to troubleshoot due to distributed logs and complex execution contexts.&lt;/p&gt;

&lt;p&gt;This month introduces fixes for RemoteShell-related NPEs, making task failures easier to understand and resolve.&lt;/p&gt;

&lt;p&gt;Related PR:&lt;br&gt;
&lt;a href="https://github.com/apache/dolphinscheduler/pull/18210" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18210&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Improved Dependency Conflict Management for Task Plugins
&lt;/h3&gt;

&lt;p&gt;Plugins such as AliyunServerlessSpark previously suffered from dependency conflicts that could lead to ClassNotFound or compatibility issues.&lt;/p&gt;

&lt;p&gt;Enhancements to dependency management and exception handling improve overall plugin reliability.&lt;/p&gt;

&lt;p&gt;Related PR:&lt;br&gt;
&lt;a href="https://github.com/apache/dolphinscheduler/pull/18180" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18180&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  5. Faster and More Reliable CI and Unit Testing
&lt;/h3&gt;

&lt;p&gt;This is not a user-facing feature, but it matters greatly.&lt;/p&gt;

&lt;p&gt;More stable CI pipelines catch problems before code is merged, and stronger testing reduces the likelihood of production incidents.&lt;/p&gt;

&lt;p&gt;Related PRs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/apache/dolphinscheduler/pull/18213" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18213&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/apache/dolphinscheduler/pull/18214" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18214&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/apache/dolphinscheduler/pull/18205" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18205&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  6. More Flexible Region and Endpoint Support for AWS S3 Remote Logs
&lt;/h3&gt;

&lt;p&gt;Users relying on S3-compatible storage services or private endpoints now have greater flexibility when configuring regions and endpoints.&lt;/p&gt;

&lt;p&gt;This reduces troubleshooting time for connectivity issues caused by storage configuration differences.&lt;/p&gt;

&lt;p&gt;Related PR:&lt;br&gt;
&lt;a href="https://github.com/apache/dolphinscheduler/pull/18268" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18268&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Upgrade and Validation Recommendations
&lt;/h2&gt;

&lt;p&gt;This report is based on PRs merged into the &lt;strong&gt;dev branch during May 2026&lt;/strong&gt;, making it valuable for tracking development trends and performing early validation.&lt;/p&gt;

&lt;p&gt;If you are running DolphinScheduler in production, prioritize upgrades based on risk:&lt;/p&gt;
&lt;h3&gt;
  
  
  Recommended for Immediate Attention
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Master failover improvements&lt;/li&gt;
&lt;li&gt;Authorization and security-related fixes&lt;/li&gt;
&lt;li&gt;Task plugin stability enhancements&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Can Be Adopted as Needed
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;CI and testing optimizations&lt;/li&gt;
&lt;li&gt;Documentation and formatting updates&lt;/li&gt;
&lt;li&gt;Return-type migration and engineering quality improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since all changes were merged into the &lt;code&gt;dev&lt;/code&gt; branch, validation in testing or integration environments is recommended:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin dev
git checkout dev
git pull &lt;span class="nt"&gt;--rebase&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Focus regression testing on the following scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Master restart and failover recovery&lt;/li&gt;
&lt;li&gt;Critical API authorization validation&lt;/li&gt;
&lt;li&gt;Common task plugins such as RemoteShell and ServerlessSpark&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Contributor Acknowledgements
&lt;/h2&gt;

&lt;p&gt;Thanks to all contributors who submitted and merged PRs to Apache DolphinScheduler during May 2026.&lt;/p&gt;

&lt;p&gt;Your contributions continue to improve the platform's stability, usability, and ecosystem capabilities.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;GitHub Username&lt;/th&gt;
&lt;th&gt;Main Contribution&lt;/th&gt;
&lt;th&gt;Merged PRs&lt;/th&gt;
&lt;th&gt;+Lines&lt;/th&gt;
&lt;th&gt;-Lines&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;@ruanwenjun&lt;/td&gt;
&lt;td&gt;Test Cases&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;7367&lt;/td&gt;
&lt;td&gt;6506&lt;/td&gt;
&lt;td&gt;349.69&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@SbloodyS&lt;/td&gt;
&lt;td&gt;Test Cases&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;2503&lt;/td&gt;
&lt;td&gt;1988&lt;/td&gt;
&lt;td&gt;45.83&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@hiSandog&lt;/td&gt;
&lt;td&gt;Documentation&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;15.12&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@leocook&lt;/td&gt;
&lt;td&gt;Debug &amp;amp; Fix&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;td&gt;29&lt;/td&gt;
&lt;td&gt;9.15&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@includetts&lt;/td&gt;
&lt;td&gt;Debug &amp;amp; Fix&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;9.06&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@llphxd&lt;/td&gt;
&lt;td&gt;Documentation&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;9.02&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;@wcmolin&lt;/td&gt;
&lt;td&gt;Test Cases&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;78&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;8.26&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  In-Depth Analysis of Key Technical Changes
&lt;/h2&gt;

&lt;p&gt;A total of &lt;strong&gt;50 PRs&lt;/strong&gt; were merged this month.&lt;/p&gt;

&lt;p&gt;The primary focus areas include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stability&lt;/li&gt;
&lt;li&gt;Security and Authorization&lt;/li&gt;
&lt;li&gt;Plugin Reliability&lt;/li&gt;
&lt;li&gt;CI and Testing Efficiency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To help readers quickly understand the most important developments, the following section analyzes five representative changes in detail.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. [Fix-18197][Master] Fix master failover lock leak (#18207)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Link: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18207" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18207&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Author: @ruanwenjun&lt;/li&gt;
&lt;li&gt;Base/Head: dev ← dev_wenjun_fix18197&lt;/li&gt;
&lt;li&gt;Diff Stats: +171 / -10&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Background and Challenges
&lt;/h4&gt;

&lt;p&gt;Master failover relies on distributed locks to ensure that failover for a given address is not executed concurrently.&lt;/p&gt;

&lt;p&gt;If lock release logic is incorrect, lock nodes may leak, preventing future failover operations and leaving the cluster unable to resume scheduling after failures.&lt;/p&gt;

&lt;h4&gt;
  
  
  Design and Implementation
&lt;/h4&gt;

&lt;p&gt;The lock acquisition interface was redesigned to return an AutoCloseable handle.&lt;/p&gt;

&lt;p&gt;Using try-with-resources guarantees symmetric acquire/release behavior.&lt;/p&gt;

&lt;p&gt;Additionally, callers now retain the exact lock path, preventing subtle mistakes such as releasing parent paths.&lt;/p&gt;

&lt;h4&gt;
  
  
  Suggested Metrics
&lt;/h4&gt;

&lt;p&gt;Simulate failover storms in a three-Master cluster by repeatedly issuing kill -9 and automatic restarts.&lt;/p&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Failover success rate&lt;/li&gt;
&lt;li&gt;Mean Time To Recovery (MTTR)&lt;/li&gt;
&lt;li&gt;Failover thread blocking duration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Registry lock node count should also be monitored, as lock leaks accumulate over time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Compatibility and Rollback
&lt;/h4&gt;

&lt;p&gt;Interface signature changes may affect callers.&lt;/p&gt;

&lt;p&gt;Rollback is straightforward but requires cleanup of leaked lock nodes to prevent continued service disruption.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgonebge04iyekvs87o0f.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgonebge04iyekvs87o0f.jpg" width="670" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. [Fix][API] Add missing project authorization on view-gantt/view-variables and trigger workflow APIs (#18212)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Link: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18212" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18212&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Author: @ruanwenjun&lt;/li&gt;
&lt;li&gt;Base/Head: dev ← dev_wenjun_fixCvePermissionCheck&lt;/li&gt;
&lt;li&gt;Diff Stats: +321 / -16&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Background and Challenges
&lt;/h4&gt;

&lt;p&gt;Workflow APIs without project-level authorization checks can create privilege escalation risks.&lt;/p&gt;

&lt;p&gt;In multi-tenant enterprise environments, this becomes a serious security concern.&lt;/p&gt;

&lt;h4&gt;
  
  
  Design and Implementation
&lt;/h4&gt;

&lt;p&gt;Authorization validation was added to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;view-gantt&lt;/li&gt;
&lt;li&gt;view-variables&lt;/li&gt;
&lt;li&gt;trigger workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Permission checks are enforced consistently through Controller and Service layers.&lt;/p&gt;

&lt;h4&gt;
  
  
  Suggested Validation
&lt;/h4&gt;

&lt;p&gt;Benchmark authorization overhead before and after implementation.&lt;/p&gt;

&lt;p&gt;Security regression tests should include cross-project access attempts.&lt;/p&gt;

&lt;h4&gt;
  
  
  Best Practices
&lt;/h4&gt;

&lt;p&gt;Enterprise users should enable stricter tenant isolation policies and audit sensitive API operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwht31p9yhh52f24lwee.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnwht31p9yhh52f24lwee.jpg" width="799" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. [Fix-18201][TaskPlugin] Fix RemoteShell task NullPointerException and… (#18210)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Link: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18210" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18210&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Author: @leocook&lt;/li&gt;
&lt;li&gt;Base/Head: dev ← fix-18201-remoteshell-npe&lt;/li&gt;
&lt;li&gt;Diff Stats: +34 / -29&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Background and Challenges
&lt;/h4&gt;

&lt;p&gt;RemoteShell tasks are commonly used for operations and integration workloads.&lt;/p&gt;

&lt;p&gt;Network interruptions, command output handling differences, and SSH channel inconsistencies can easily lead to NPEs and incomplete logs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Design and Implementation
&lt;/h4&gt;

&lt;p&gt;Input/output stream handling for SSH channels was improved to eliminate null pointer scenarios.&lt;/p&gt;

&lt;p&gt;Exception handling paths were also enhanced to preserve root-cause information.&lt;/p&gt;

&lt;h4&gt;
  
  
  Suggested Validation
&lt;/h4&gt;

&lt;p&gt;Inject failures such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remote disconnections&lt;/li&gt;
&lt;li&gt;Empty output streams&lt;/li&gt;
&lt;li&gt;Immediate command termination&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execute 1,000 test runs and compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NPE occurrence rates&lt;/li&gt;
&lt;li&gt;Log completeness&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Risks and Rollback
&lt;/h4&gt;

&lt;p&gt;Changes are isolated to the plugin layer and are relatively easy to revert.&lt;/p&gt;

&lt;p&gt;Regression tests should continue covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Empty output&lt;/li&gt;
&lt;li&gt;Large output&lt;/li&gt;
&lt;li&gt;Non-zero exit codes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. [Fix-18177][Task Plugin] Fix AliyunServerlessSpark plugin dependency conflicts and improve exception handling (#18180)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Link: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18180" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18180&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Author: @includetts&lt;/li&gt;
&lt;li&gt;Base/Head: dev ← fix/aliyun-serverless-spark-deps-v2&lt;/li&gt;
&lt;li&gt;Diff Stats: +16 / -6&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Background and Challenges
&lt;/h4&gt;

&lt;p&gt;Dependency conflicts are classic runtime problems that often manifest as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NoSuchMethodError&lt;/li&gt;
&lt;li&gt;NoSuchFieldError&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are difficult to reproduce because they only occur under specific dependency combinations.&lt;/p&gt;

&lt;h4&gt;
  
  
  Design and Implementation
&lt;/h4&gt;

&lt;p&gt;Critical dependency versions were corrected and exception wrapping improved.&lt;/p&gt;

&lt;p&gt;Users can now directly identify conflicting classes and methods from logs.&lt;/p&gt;

&lt;h4&gt;
  
  
  Suggested Validation
&lt;/h4&gt;

&lt;p&gt;Execute smoke tests under multiple Hadoop and Spark dependency trees.&lt;/p&gt;

&lt;p&gt;Measure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Startup success rate&lt;/li&gt;
&lt;li&gt;Exception readability&lt;/li&gt;
&lt;li&gt;Time-to-diagnosis&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Best Practices
&lt;/h4&gt;

&lt;p&gt;Production environments should consider dependency isolation techniques such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shading&lt;/li&gt;
&lt;li&gt;Relocation&lt;/li&gt;
&lt;li&gt;Dedicated ClassLoaders&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5. [Chore] Unit-Test performance optimize (#18213)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Link: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18213" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18213&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Author: @SbloodyS&lt;/li&gt;
&lt;li&gt;Base/Head: dev ← ut_performance_optimize&lt;/li&gt;
&lt;li&gt;Diff Stats: +22 / -6&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Background and Challenges
&lt;/h4&gt;

&lt;p&gt;Slow, flaky, or frequently skipped tests delay problem detection until production deployment.&lt;/p&gt;

&lt;p&gt;Testing infrastructure directly impacts community development speed and software quality.&lt;/p&gt;

&lt;h4&gt;
  
  
  Design and Implementation
&lt;/h4&gt;

&lt;p&gt;Unit test execution and CI configurations were optimized.&lt;/p&gt;

&lt;p&gt;Temporary safeguards were also introduced to maintain CI stability during environmental issues.&lt;/p&gt;

&lt;h4&gt;
  
  
  Suggested Validation
&lt;/h4&gt;

&lt;p&gt;Compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total CI duration&lt;/li&gt;
&lt;li&gt;Number of executed unit tests&lt;/li&gt;
&lt;li&gt;Percentage of skipped tests&lt;/li&gt;
&lt;li&gt;Flaky test rerun counts&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Risks and Rollback
&lt;/h4&gt;

&lt;p&gt;Temporary test disablement should always include a documented recovery plan.&lt;/p&gt;

&lt;p&gt;Conditions for re-enabling tests should be tracked through issues and PRs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appendix
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;PR #18204: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18204" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18204&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18208: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18208" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18208&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18206: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18206" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18206&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18207: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18207" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18207&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18205: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18205" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18205&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18213: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18213" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18213&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18209: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18209" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18209&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18180: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18180" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18180&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18212: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18212" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18212&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18210: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18210" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18210&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18214: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18214" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18214&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18221: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18221" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18221&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18218: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18218" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18218&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18225: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18225" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18225&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18227: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18227" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18227&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18241: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18241" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18241&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18240: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18240" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18240&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18226: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18226" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18226&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18228: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18228" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18228&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18229: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18229" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18229&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18232: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18232" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18232&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18223: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18223" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18223&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18230: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18230" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18230&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18234: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18234" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18234&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18242: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18242" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18242&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18236: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18236" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18236&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18233: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18233" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18233&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18245: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18245" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18245&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18250: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18250" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18250&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18251: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18251" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18251&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18252: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18252" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18252&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18257: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18257" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18257&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18270: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18270" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18270&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18271: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18271" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18271&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18258: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18258" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18258&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18253: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18253" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18253&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18260: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18260" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18260&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18259: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18259" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18259&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18256: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18256" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18256&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18263: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18263" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18263&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18262: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18262" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18262&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18261: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18261" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18261&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18254: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18254" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18254&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18279: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18279" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18279&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18284: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18284" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18284&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18288: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18288" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18288&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18268: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18268" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18268&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18296: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18296" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18296&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18300: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18300" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18300&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PR #18301: &lt;a href="https://github.com/apache/dolphinscheduler/pull/18301" rel="noopener noreferrer"&gt;https://github.com/apache/dolphinscheduler/pull/18301&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>apachedolphinscheduler</category>
      <category>opensource</category>
      <category>datascience</category>
      <category>data</category>
    </item>
    <item>
      <title>Upgrading DolphinScheduler Across Major Versions: From 3.1.3 to 3.4.1 via API Automation</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Thu, 21 May 2026 07:22:53 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/upgrading-dolphinscheduler-across-major-versions-from-313-to-341-via-api-automation-1no3</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/upgrading-dolphinscheduler-across-major-versions-from-313-to-341-via-api-automation-1no3</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30rvscogzk63nkvc6m1a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30rvscogzk63nkvc6m1a.jpg" width="800" height="359"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Background: Why Perform a Major Version Upgrade?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Existing Environment
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Current DolphinScheduler Version:&lt;/strong&gt; 3.1.3&lt;br&gt;
&lt;strong&gt;Current SeaTunnel Version:&lt;/strong&gt; 2.1.3&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deployment Scale:&lt;/strong&gt;&lt;br&gt;
1 Master + 2 Workers, with over 3,700 workflow definitions and more than 20,000 scheduled tasks executed daily.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Years in Production:&lt;/strong&gt;&lt;br&gt;
The system has been running stably for over three years.&lt;/p&gt;

&lt;h3&gt;
  
  
  Drivers Behind the Upgrade
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Functional Requirements:&lt;/strong&gt;&lt;br&gt;
With growing business demands, the limitations of the current version became increasingly apparent, including architectural design constraints, metadata database processing bottlenecks, and insufficient server resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Community Support:&lt;/strong&gt;&lt;br&gt;
The official community recommends adopting the latest stable release to obtain better technical support.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance Optimization:&lt;/strong&gt;&lt;br&gt;
Version 3.4.1 delivers significant improvements in scheduling performance and system stability.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Why We Did Not Use the Official Upgrade Path
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Large Version Gap:&lt;/strong&gt;&lt;br&gt;
The upgrade path would require multiple intermediate upgrades:&lt;br&gt;
3.1.3 → 3.2.0 → 3.3.0 → 3.4.1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Production Environment Constraints:&lt;/strong&gt;&lt;br&gt;
Multiple maintenance windows were unacceptable due to strict business continuity requirements.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Architectural Change Risks:&lt;/strong&gt;&lt;br&gt;
Risks included resource center refactoring, metadata schema changes, and compatibility issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Workload Considerations:&lt;/strong&gt;&lt;br&gt;
With thousands of workflows, manually rebuilding tasks would require enormous effort, making automation essential.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Overall Migration Strategy: Bypassing the Official Upgrade Path with a “Rebuild + API” Approach
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Core Idea
&lt;/h3&gt;

&lt;p&gt;Instead of pursuing an “in-place incremental upgrade,” we adopted a “new environment + data migration” strategy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The old 3.1.3 cluster continued running without impacting production workloads.&lt;/li&gt;
&lt;li&gt;A brand-new 3.4.1 cluster was deployed to ensure a clean architecture.&lt;/li&gt;
&lt;li&gt;Custom scripts were developed to retrieve workflow definitions and task configurations from the old-version APIs.&lt;/li&gt;
&lt;li&gt;New-version APIs were used to batch-create workflows in the new cluster.&lt;/li&gt;
&lt;li&gt;Business scheduling traffic was gradually switched to the new environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.2 Comparison of Advantages and Risks
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Dimension&lt;/th&gt;
&lt;th&gt;Official Upgrade Approach&lt;/th&gt;
&lt;th&gt;Rebuild + API Approach&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Downtime&lt;/td&gt;
&lt;td&gt;Multiple upgrades with cumulative downtime potentially lasting hours or even days&lt;/td&gt;
&lt;td&gt;Nearly seamless cutover by stopping old schedules and enabling new ones&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rollback Difficulty&lt;/td&gt;
&lt;td&gt;Difficult, as the database schema has already changed&lt;/td&gt;
&lt;td&gt;Easy, since the old environment remains intact&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Consistency&lt;/td&gt;
&lt;td&gt;Requires validation of all schema migrations&lt;/td&gt;
&lt;td&gt;Only core business data (workflow definitions) is migrated; historical execution records are excluded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version Compatibility&lt;/td&gt;
&lt;td&gt;Must handle compatibility issues across all intermediate versions&lt;/td&gt;
&lt;td&gt;Directly adapts to 3.4.1 with only necessary parameter transformations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workload&lt;/td&gt;
&lt;td&gt;Requires repeated validation cycles&lt;/td&gt;
&lt;td&gt;Effort mainly concentrated on script development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Suitable Scenarios&lt;/td&gt;
&lt;td&gt;Minor version upgrades&lt;/td&gt;
&lt;td&gt;Major version jumps and large-scale task migration&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  3. Detailed Implementation Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Environment Preparation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  3.1.1 Deploying the New Environment
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Deploy a brand-new DolphinScheduler 3.4.1 cluster.&lt;/li&gt;
&lt;li&gt;Configure dependencies such as the database and Registry. ZooKeeper was deprecated and replaced with JDBC Registry.&lt;/li&gt;
&lt;li&gt;Configure required components such as DataX and SeaTunnel.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Understand key changes in the new version, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SeaTunnel 2.1.3 integration startup mode changed from Spark engine execution to &lt;code&gt;start-seatunnel-spark.sh&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;Default configurations such as tenants, worker groups, and environments are now managed through project preferences;&lt;/li&gt;
&lt;li&gt;Parameter passing behavior changed: downstream tasks must explicitly define &lt;code&gt;IN&lt;/code&gt; parameters to receive upstream variable values.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Verify the basic functionality of the new environment and manually validate representative workflows.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  3.1.2 API Access Configuration
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Configure API access permissions in the new environment by creating new tokens in token management.&lt;/li&gt;
&lt;li&gt;Obtain administrator tokens for API calls.&lt;/li&gt;
&lt;li&gt;Verify API connectivity.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.2 Metadata Database Initialization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Replicating Base Tables:&lt;/strong&gt;
Rebuild foundational metadata tables in the new metadata database according to the old-version configuration, including preserving IDs wherever possible. This significantly reduced modification complexity during script-based workflow restoration.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Verification Item&lt;/th&gt;
&lt;th&gt;Table&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tenant Table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;t_ds_tenant&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Project Table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;t_ds_project&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User Table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;t_ds_user&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Environment Tables&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;t_ds_environment&lt;/code&gt;, &lt;code&gt;t_ds_environment_worker_group_relation&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worker Group Table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;t_ds_worker_group&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data Source Table&lt;/td&gt;
&lt;td&gt;&lt;code&gt;t_ds_datasource&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  3.3 Migration Script Development
&lt;/h3&gt;

&lt;h4&gt;
  
  
  3.3.1 Preliminary Preparation and Testing
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Categorize workflows into template-based and non-template-based tasks.&lt;/li&gt;
&lt;li&gt;Select representative workflows and execute them in the new environment to verify successful execution and data synchronization accuracy.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  3.3.2 Code Development — Reading Original Workflow Definitions
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
 &lt;span class="c1"&gt;// Retrieve all workflows and process them iteratively&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;processDefinitionUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OLD_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/dolphinscheduler/projects/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;oldProjectCode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
                &lt;span class="s"&gt;"/process-definition/query-process-definition-list"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
        &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"projectCode"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oldProjectCode&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;pdRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClientUtilOld&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doGetRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;processDefinitionUrl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;JSONObject&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dataList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parseResDataToList&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdRes&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dataList&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;oldWFCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;job&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mapPara&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;oldurl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;OLD_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/dolphinscheduler/projects/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;oldProjectCode&lt;/span&gt;
                    &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/process-definition/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;oldWFCode&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;mapPara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oldWFCode&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;mapPara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"projectCode"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;oldProjectCode&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClientUtilOld&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doGetRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldurl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapPara&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;jsonObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JSONObject&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;jsonObject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;processDefinition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getJSONObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"processDefinition"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;JSONArray&lt;/span&gt; &lt;span class="n"&gt;processTaskRelationList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getJSONArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"processTaskRelationList"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;JSONArray&lt;/span&gt; &lt;span class="n"&gt;taskDefinitionList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getJSONArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"taskDefinitionList"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// TODO: generate new task codes and replace old ones&lt;/span&gt;
            &lt;span class="c1"&gt;// Populate workflow information and create workflows&lt;/span&gt;
            &lt;span class="n"&gt;createWF&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;processDefinition&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;processTaskRelationList&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskDefinitionList&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;NEW_IP&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newProjectCode&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3.3.3 Creating Workflows via API
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="c1"&gt;// Generate task codes based on task count&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;taskCnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskDefinitionList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;taskCodeList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskDefinitionList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JSONObject&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"code"&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// TODO: generate task codes&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;taskCodeUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;NEW_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/dolphinscheduler/projects/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;newProjectCode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/task-definition/gen-task-codes"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;taskCodeMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
            &lt;span class="c1"&gt;// Generate n task codes&lt;/span&gt;
            &lt;span class="n"&gt;taskCodeMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"genNum"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;valueOf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taskCnt&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;codeData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClientUtilNew&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doGetRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;taskCodeUrl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskCodeMap&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;codes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;codeData&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="nc"&gt;JSONArray&lt;/span&gt; &lt;span class="n"&gt;taskCodeArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parseArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;codes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

&lt;span class="c1"&gt;// Add downstream input parameters based on actual task requirements&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;taskDefinitionList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;logTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JSONObject&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;taskDefinitionList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="err"&gt;“&lt;/span&gt;&lt;span class="nc"&gt;Condition&lt;/span&gt; &lt;span class="nc"&gt;Logic&lt;/span&gt;&lt;span class="err"&gt;”&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;taskParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getJSONObject&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"taskParams"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="nc"&gt;JSONArray&lt;/span&gt; &lt;span class="n"&gt;localParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskParams&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getJSONArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"localParams"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                    &lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;hiveParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JSONObject&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                    &lt;span class="n"&gt;hiveParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"prop"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"hiveAmount"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="n"&gt;hiveParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"direct"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"IN"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="n"&gt;hiveParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"VARCHAR"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="n"&gt;hiveParam&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="n"&gt;localParams&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hiveParam&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                    &lt;span class="n"&gt;logTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"taskParamList"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;localParams&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                    &lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;paramMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;JSONObject&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
                    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Object&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;localParams&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                        &lt;span class="nc"&gt;JSONObject&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;JSONObject&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
                        &lt;span class="n"&gt;paramMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"prop"&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="n"&gt;param&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
                    &lt;span class="o"&gt;}&lt;/span&gt;

                    &lt;span class="n"&gt;logTask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"taskParamMap"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;paramMap&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                    &lt;span class="o"&gt;....&lt;/span&gt;


&lt;span class="c1"&gt;// Replace required parameters such as task code and SeaTunnel execution engine&lt;/span&gt;
 &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;taskCodeList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;size&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;oldCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskCodeList&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;newCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskCodeArr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Replace task code&lt;/span&gt;
                &lt;span class="c1"&gt;// Replace SeaTunnel engine: "SPARK" -&amp;gt; "start-seatunnel-spark.sh"&lt;/span&gt;
                &lt;span class="n"&gt;taskDefinitionListJsonStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskDefinitionListJsonStr&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\"code\":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;oldCode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\"code\":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;newCode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"\"engine\":\"SPARK\","&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"\"startupScript\":\"start-seatunnel-spark.sh\","&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;taskRelationListJsonStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;taskRelationListJsonStr&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TaskCode\":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;oldCode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"TaskCode\":"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;newCode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;locationsJsonStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;locationsJsonStr&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replace&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldCode&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;newCode&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"taskDefinitionJson"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskDefinitionListJsonStr&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"taskRelationJson"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;taskRelationListJsonStr&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"locations"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;locationsJsonStr&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;processDefinition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tenantCode"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"omm"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"executionType"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;processDefinition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"executionType"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;processDefinition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;processDefinition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"globalParams"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;processDefinition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"globalParams"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
            &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"timeout"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;processDefinition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getString&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"timeout"&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;processDefinitionUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;NEW_URL&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/dolphinscheduler/projects/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;newProjectCode&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/workflow-definition"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
            &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;processDefinitionRes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpClientUtilNew&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;doPostRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;processDefinitionUrl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3.4 Migration Execution
&lt;/h3&gt;

&lt;h4&gt;
  
  
  3.4.1 Migration Procedure
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Back Up Old Scheduling Tables:&lt;/strong&gt;&lt;br&gt;
Example: &lt;code&gt;t_ds_schedules_20260416_10&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Select a Pilot Project:&lt;/strong&gt;&lt;br&gt;
Choose a project with moderate workload and limited business impact.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Migrate Workflow Definitions:&lt;/strong&gt;&lt;br&gt;
Migrate approximately 200 workflow definitions, including scheduling configurations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deploy Workflows Without Enabling Schedules:&lt;/strong&gt;&lt;br&gt;
Deploy workflows first without activating schedules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manual Validation:&lt;/strong&gt;&lt;br&gt;
Execute workflows manually in batches and verify conflicts with the original cluster. Since most workflows run daily, hourly, or every 15 minutes, conflicts were minimal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Investigate Failed Tasks:&lt;/strong&gt;&lt;br&gt;
Analyze root causes, fix issues, and rerun failed workflows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enable Scheduling Configurations:&lt;/strong&gt;&lt;br&gt;
Enable schedules after all workflows pass validation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Disable Old Cluster Scheduling:&lt;/strong&gt;&lt;br&gt;
After confirming stable operation in the new environment, disable corresponding schedules in the old cluster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Migrate Project by Project, Batch by Batch&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  3.4.2 Migration Execution Results
&lt;/h4&gt;

&lt;p&gt;Following this process, we first selected a representative project containing 199 workflows. After migration, it was tested in production for one week without issues.&lt;/p&gt;

&lt;p&gt;Subsequently, we completed migration for 50 projects, totaling approximately 3,700 workflows, within about 10 days.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tracking Table&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;No.&lt;/th&gt;
&lt;th&gt;Project Name&lt;/th&gt;
&lt;th&gt;Project Code&lt;/th&gt;
&lt;th&gt;Workflow Count&lt;/th&gt;
&lt;th&gt;Progress&lt;/th&gt;
&lt;th&gt;Remarks&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Project 1&lt;/td&gt;
&lt;td&gt;13*******&lt;/td&gt;
&lt;td&gt;199&lt;/td&gt;
&lt;td&gt;Completed on 04/16&lt;/td&gt;
&lt;td&gt;One-week stability test completed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Project 2&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;td&gt;...&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h4&gt;
  
  
  3.4.3 Runtime Status
&lt;/h4&gt;

&lt;p&gt;The new cluster has now been running for nearly one month.&lt;/p&gt;

&lt;p&gt;Previously, scheduling delays ranged from 10 seconds to over one minute in severe cases. After the upgrade, scheduling latency has been virtually eliminated.&lt;/p&gt;

&lt;p&gt;Issues related to missing scheduling instances have also not reoccurred.&lt;/p&gt;

&lt;p&gt;So far, the system has been running smoothly without any identified problems, and continuous monitoring remains in place.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Risk Control and Contingency Planning
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 Major Risks
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Risk of Data Loss:&lt;/strong&gt;&lt;br&gt;
Some configurations could potentially be missed during migration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compatibility Issues:&lt;/strong&gt;&lt;br&gt;
Certain configurations supported in the old version may not be supported in the new version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Business Interruption Risks:&lt;/strong&gt;&lt;br&gt;
Scheduling delays could occur during the switchover process.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2 Contingency Plans
&lt;/h3&gt;

&lt;h4&gt;
  
  
  4.2.1 Rollback Strategy
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Immediately stop scheduling in the new environment.&lt;/li&gt;
&lt;li&gt;Restore scheduling services in the old environment.&lt;/li&gt;
&lt;li&gt;Analyze root causes and retry after issue resolution.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  4.2.2 Data Backup
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Perform a complete backup of the old environment database.&lt;/li&gt;
&lt;li&gt;Back up the initial configuration of the new environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Conclusion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Project Outcomes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Successfully completed a cross-version upgrade with zero business interruption.&lt;/li&gt;
&lt;li&gt;Automated migration scripts significantly improved efficiency and reduced manual errors.&lt;/li&gt;
&lt;li&gt;The new version delivered major performance gains and substantial stability improvements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.2 Lessons Learned
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Major version upgrades require comprehensive evaluation of architectural changes.&lt;/li&gt;
&lt;li&gt;API-based migration is highly suitable for configuration migration, though parameter compatibility must be handled carefully.&lt;/li&gt;
&lt;li&gt;Thorough testing and validation are critical to success.&lt;/li&gt;
&lt;li&gt;A robust monitoring system is essential for operational stability.&lt;/li&gt;
&lt;li&gt;Comprehensive documentation is invaluable for long-term maintenance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.3 Future Plans
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The current upgrade primarily addressed DolphinScheduler scheduling bottlenecks. To align with upcoming Spark cluster upgrades, the next step will be upgrading SeaTunnel from version 2.1.3 to 2.3.12, most likely using the same migration methodology.&lt;/li&gt;
&lt;li&gt;Explore automated testing solutions.&lt;/li&gt;
&lt;li&gt;Share migration experience with other teams.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>apachedolphinscheduler</category>
      <category>upgade</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>DolphinScheduler Agent Is Now Open-Source! Bringing Self-Healing Automation to DataOps</title>
      <dc:creator>Chen Debra</dc:creator>
      <pubDate>Mon, 18 May 2026 03:17:26 +0000</pubDate>
      <link>https://dev.to/chen_debra_3060b21d12b1b0/dolphinscheduler-agent-is-now-open-source-bringing-self-healing-automation-to-dataops-1of8</link>
      <guid>https://dev.to/chen_debra_3060b21d12b1b0/dolphinscheduler-agent-is-now-open-source-bringing-self-healing-automation-to-dataops-1of8</guid>
      <description>&lt;p&gt;At the 2026 Apache DolphinScheduler Meetup technical session, the &lt;strong&gt;DolphinScheduler Agent&lt;/strong&gt; solution presented by Liu Xiaodong immediately became one of the hottest topics in the community. This end-to-end system, connecting “group alert → intelligent diagnosis → automatic recovery → reporting loop,” effectively solves the fragmentation, high manual overhead, and constant context switching of traditional operations workflows, bringing big data incident handling from the era of “manual firefighting” into the age of “intelligent autonomous operations.”&lt;/p&gt;

&lt;p&gt;The project’s core supporting tool, &lt;strong&gt;dolphinscheduler-cli (dsctl)&lt;/strong&gt;, has now officially been open-sourced on GitHub and is freely available for all developers!&lt;/p&gt;

&lt;p&gt;Watch the Replay: &lt;a href="https://youtu.be/mnGC-XOf8xU" rel="noopener noreferrer"&gt;https://youtu.be/mnGC-XOf8xU&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Pain of Traditional Operations: Slow Recovery Isn’t About Commands — It’s About Fragmented Context
&lt;/h2&gt;

&lt;p&gt;When using Apache DolphinScheduler in daily production, handling failed tasks has always been a major burden for operations teams.&lt;/p&gt;

&lt;p&gt;The workflow is all too familiar:&lt;/p&gt;

&lt;p&gt;A Feishu alert pops up → open the DS UI to check instance status → inspect logs to locate the failure → compare with the Runbook → manually decide what to do → return to the group chat and reply with the result...&lt;/p&gt;

&lt;p&gt;What truly slows down efficiency is not executing a command itself, but the &lt;strong&gt;constant loss of context across multiple systems&lt;/strong&gt;. Facts, evidence, and risks are scattered across different tools, forcing operators to spend enormous time “searching for information, stitching logic together, and rebuilding context.” Collaboration breaks frequently, troubleshooting costs soar, and incident recovery cycles become unnecessarily long.&lt;/p&gt;

&lt;p&gt;With DolphinScheduler Agent, all of this changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Major Upgrade: From Fragmented Human Coordination to an Intelligent End-to-End Closed Loop
&lt;/h2&gt;

&lt;p&gt;To solve these operational gaps, the goal of the DolphinScheduler Agent solution is crystal clear:&lt;/p&gt;

&lt;p&gt;Transform every failure alert into a continuous, traceable, and reusable handling workflow.&lt;/p&gt;

&lt;p&gt;The old model treated alerts, UI pages, logs, group chats, and postmortems as isolated systems heavily dependent on human coordination.&lt;/p&gt;

&lt;p&gt;The new model starts from a Feishu alert and flows through &lt;strong&gt;Channel conversations, intelligent orchestration, execution control, verification, and automated reporting&lt;/strong&gt;, forming a seamless end-to-end process from trigger to resolution — without requiring engineers to jump repeatedly between systems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1kkebzhotaiqpwxonf1c.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1kkebzhotaiqpwxonf1c.jpg" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simply put:&lt;/p&gt;

&lt;p&gt;Once an alert is triggered, the Agent automatically takes over.&lt;br&gt;
Once handling is complete, it automatically replies in the group and generates a full incident report.&lt;/p&gt;

&lt;p&gt;Operations engineers only need to review the conclusion instead of “running around everywhere.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Five-Layer Core Architecture: Not Just Scripts, but a Safe and Controllable Intelligent Control Chain
&lt;/h2&gt;

&lt;p&gt;Many people mistakenly think automated operations simply mean “bots + scripts.”&lt;/p&gt;

&lt;p&gt;However, DolphinScheduler Agent takes a much more robust and engineering-oriented approach: a &lt;strong&gt;five-layer decoupled control chain&lt;/strong&gt;. Each layer has clear responsibilities, ensuring both execution capability and strict safety boundaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. L1 Event &amp;amp; Collaboration
&lt;/h3&gt;

&lt;p&gt;Alerts directly enter Feishu threads, allowing human intervention and questioning at any time. The &lt;code&gt;workflowInstanceId&lt;/code&gt; serves as the unique incident anchor, ensuring information is never lost or fragmented.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. L2 Session Integration
&lt;/h3&gt;

&lt;p&gt;Feishu events synchronize into local sessions, maintaining full conversational context and eliminating interruptions caused by switching systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. L3 Intelligent Orchestration
&lt;/h3&gt;

&lt;p&gt;Claude Code handles information organization and invocation orchestration, while Skills encapsulate DolphinScheduler domain expertise for more accurate decision-making.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. L4 Execution Control
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;dsctl&lt;/code&gt; centrally handles the core actions of &lt;strong&gt;evidence collection, fault recovery, and result verification&lt;/strong&gt;, providing standardized, reusable, and stable command execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. L5 Governance &amp;amp; Reporting
&lt;/h3&gt;

&lt;p&gt;The system automatically generates Feishu replies, incident reports, and audit logs, balancing real-time collaboration with long-term governance and postmortem analysis.&lt;/p&gt;

&lt;p&gt;This architecture directly addresses real operational requirements:&lt;br&gt;
Only through decoupled architecture can capabilities scale reliably; only through clear boundaries can automation safely enter production environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four Core Modules: Making Self-Healing Truly Production-Ready
&lt;/h2&gt;

&lt;p&gt;Built on top of the five-layer architecture, four tightly integrated modules make the system practical, scalable, and trustworthy.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Channel: Native Feishu Entry Point for Unified Collaboration
&lt;/h3&gt;

&lt;p&gt;Feishu groups become the &lt;strong&gt;alert entrance, collaboration interface, and result feedback page&lt;/strong&gt; all in one.&lt;/p&gt;

&lt;p&gt;Agents, humans, and on-call workflows collaborate within the same thread. Group chats display concise conclusions, while detailed evidence is preserved in reports for future reference.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wryvypndgtyaybp9c0r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wryvypndgtyaybp9c0r.jpg" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Runtime: Intelligent Orchestration Engine with Decoupled Rules and Execution
&lt;/h3&gt;

&lt;p&gt;Claude Code manages conversation orchestration logic, while Skills encapsulate operational expertise such as fault response, workflow design, and data quality governance.&lt;/p&gt;

&lt;p&gt;By separating orchestration, rules, and execution into independent layers, the system becomes highly extensible and continuously evolvable.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Control Plane: dsctl as the Unified Execution Foundation
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;dsctl&lt;/code&gt; is the core execution engine powering the entire Agent system.&lt;/p&gt;

&lt;p&gt;It provides standardized CLI capabilities that can be safely invoked by automation systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Evidence collection: &lt;code&gt;doctor&lt;/code&gt; / &lt;code&gt;digest&lt;/code&gt; / &lt;code&gt;log&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Fault repair: &lt;code&gt;recover-failed&lt;/code&gt; / &lt;code&gt;edit --dry-run&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Result verification: &lt;code&gt;watch&lt;/code&gt; / &lt;code&gt;digest&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Unified outputs: fully observable, traceable, and auditable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With dsctl, manual commands become stable automation primitives.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Seven-Step Standard Closed Loop: Dual-Path Protection for Production Safety
&lt;/h2&gt;

&lt;p&gt;From alert triggering to incident reporting, the Agent strictly follows a seven-step state machine:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Alert Parsing → Diagnosis → Decision → Execution → Verification → Response → Reporting&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqokgini3nqd3ieap3ne.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiqokgini3nqd3ieap3ne.jpg" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Two execution paths guarantee safety:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Happy Path&lt;/strong&gt;&lt;br&gt;
For low-risk scenarios with sufficient evidence:&lt;br&gt;
collect evidence → generate execution plan → recover failed tasks → verify → reply in the group → generate report&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Escalation Path&lt;/strong&gt;&lt;br&gt;
For insufficient evidence, high-risk situations, or failed verification:&lt;br&gt;
escalate to human operators while preserving complete context — never falsely reporting success.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is traceable, auditable, and reviewable, enabling safe and stable production deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  📌 Safety: Four-Level Risk Governance — Safety Comes First
&lt;/h3&gt;

&lt;p&gt;In production automation, &lt;strong&gt;safety always matters more than speed&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The system classifies operations into four risk levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatically Allowed: read-only queries and log viewing&lt;/li&gt;
&lt;li&gt;Automatic + Protection: low-risk recovery operations like &lt;code&gt;recover-failed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Human Approval Required: high-risk modifications&lt;/li&gt;
&lt;li&gt;Forbidden: dangerous operations such as force-success are directly blocked&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This defines the system’s core philosophy:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The true strength of an Agent is not “daring to execute,” but knowing “when not to execute.”&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A Pragmatic Roadmap: Gradual Delegation Toward Autonomous Operations
&lt;/h2&gt;

&lt;p&gt;To ensure safe production adoption, the Agent follows a gradual empowerment strategy:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs86gvlkjo685bvdrqqdr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs86gvlkjo685bvdrqqdr.jpg" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MVP Stage&lt;/strong&gt;: read-only diagnosis + automated short replies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;V1 Stage&lt;/strong&gt;: enable low-risk automatic recovery via &lt;code&gt;recover-failed&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;V2 Stage&lt;/strong&gt;: integrate approval mechanisms for broader controllable operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;V3 Stage&lt;/strong&gt;: accumulate Runbooks and Skills for community collaboration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The true value of this solution is not a single prompt, but an entire engineering framework built around:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Channel + Skill + CLI + Report + Safety&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A reusable and portable operational architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;To help the audience better understand DolphinScheduler Agent’s capabilities, Liu Xiaodong also demonstrated a live demo during the session.&lt;/p&gt;

&lt;p&gt;Please refer to the video starting from 57:10 for the full demonstration.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎉 Official Open Source Release: dsctl Is Now Available on GitHub
&lt;/h2&gt;

&lt;p&gt;The great news is that the core project powering DolphinScheduler Agent — &lt;strong&gt;dolphinscheduler-cli (dsctl)&lt;/strong&gt; — has officially been open sourced!&lt;/p&gt;

&lt;p&gt;GitHub Repository:&lt;br&gt;
&lt;a href="https://github.com/sketchmind/dolphinscheduler-cli?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;dolphinscheduler-cli GitHub Repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project provides a complete CLI toolkit supporting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DolphinScheduler configuration and environment management&lt;/li&gt;
&lt;li&gt;Workflow authoring, lint checking, and DryRun simulation&lt;/li&gt;
&lt;li&gt;Runtime monitoring, instance inspection, and log retrieval&lt;/li&gt;
&lt;li&gt;Failure recovery, rerun handling, and batch operations&lt;/li&gt;
&lt;li&gt;Standardized outputs fully compatible with automation and Agent integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project is released under the Apache-2.0 license, supports one-line installation via &lt;code&gt;pip&lt;/code&gt;, and is compatible with mainstream DolphinScheduler versions including 3.3.2, 3.4.0, and 3.4.1.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;DolphinScheduler Agent is redefining the operational paradigm for big data systems:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free people from repetitive tasks, fragmented workflows, and endless context switching — let systems handle incidents, while humans focus on decision-making and governance.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From alert triggering to automatic recovery, automated replies, and report generation, the entire process becomes a seamless one-click closed loop.&lt;/p&gt;

&lt;p&gt;If everything runs smoothly, operations teams really can “lie back and let the system do the work.”&lt;/p&gt;

&lt;p&gt;Developers, operators, and big data engineers are all welcome to explore dsctl on GitHub and join the community in building a simpler, smarter, and more efficient future for operations.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>apachedolphinscheduler</category>
      <category>github</category>
    </item>
  </channel>
</rss>
