{"id":64788,"date":"2022-06-02T09:00:43","date_gmt":"2022-06-02T09:00:43","guid":{"rendered":"https:\/\/www.cryptocabaret.com\/?p=64788"},"modified":"2022-06-02T09:00:43","modified_gmt":"2022-06-02T09:00:43","slug":"get-started-with-cadence-an-open-source-workflow-engine","status":"publish","type":"post","link":"https:\/\/www.cryptocabaret.com\/?p=64788","title":{"rendered":"Get started with Cadence, an open source workflow engine"},"content":{"rendered":"<p><span class=\"field field--name-title field--type-string field--label-hidden\">Get started with Cadence, an open source workflow engine<\/span><br \/>\n<span class=\"field field--name-uid field--type-entity-reference field--label-hidden\"><a title=\"View user profile.\" href=\"https:\/\/opensource.com\/users\/ben-slater\" class=\"username\">Ben Slater<\/a><\/span><br \/>\n<span class=\"field field--name-created field--type-created field--label-hidden\">Thu, 06\/02\/2022 &#8211; 03:00<\/span><\/p>\n<div data-drupal-selector=\"rate-node-70044\" class=\"rate-widget-thumbs-up\" title=\"Register or Login to like.\">\n<div class=\"rate-thumbs-up-btn-up vote-pending\"><a href=\"https:\/\/opensource.com\/user\/register\">Register<\/a> or <a href=\"https:\/\/opensource.com\/user\/login?current=\/rss.xml\">Login<\/a> to like<\/div>\n<div class=\"rate-score\"><a href=\"https:\/\/opensource.com\/user\/register\">Register<\/a> or <a href=\"https:\/\/opensource.com\/user\/login?current=\/rss.xml\">Login<\/a> to like<\/div>\n<\/div>\n<div class=\"clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item\">\n<p>Modern applications require complicated interactions between long-running business processes, internal services, and third-party APIs. To say it&#8217;s been a challenge for developers is putting it mildly. Managing these processes means tracking complex states, preparing responses to asynchronous events, and communicating with often unreliable external dependencies.<\/p>\n<p>Developers typically take on these complex challenges with solutions that are just as convoluted, assembling unwieldy systems that leverage stateless services, databases, retry algorithms, and job scheduling queues. Because these complex systems obscure their own business logic, availability issues are common, often stemming from the application&#8217;s dependence on scattered and unproven components. Developer productivity is regularly sacrificed to keep these sprawling, troubled systems from collapsing.<\/p>\n<h2>Designing a distributed application<\/h2>\n<p>Cadence solves these issues by offering a highly scalable fault-oblivious code platform. Cadence abstracts away the usual challenges of implementing fault tolerance and durability with its fault oblivious code.<\/p>\n<p>A standard Cadence application includes a Cadence service, workflow, activity workers, and external clients. If needed, it&#8217;s acceptable to co-locate the roles of workflow workers, activity workers, and external clients in a single application process.<\/p>\n<p><strong>Cadence Service<\/strong><\/p>\n<article class=\"align-center media media--type-image media--view-mode-default\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2022\/06\/cadence1.png\" width=\"1429\" height=\"941\" alt=\"Image of client application and Cadence service\" loading=\"lazy\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>(Ben Slater, CC BY-SA 4.0)<\/p>\n<\/div>\n<\/article>\n<p>Cadence is centered on its multi-tenant service and the high scalability it enables. A strongly typed <a href=\"https:\/\/github.com\/uber\/cadence-idl\/tree\/master\/proto\/uber\/cadence\/api\/v1\">gRPC API<\/a> exposes all Cadence service functionality. A Cadence cluster can run multiple services on multiple nodes, including:<\/p>\n<ul>\n<li><strong>Front end:<\/strong> A stateless service that handles incoming worker requests, with instances backed by an external load balancer.<\/li>\n<li><strong>History service:<\/strong> Handles core logic for workflow steps and activity orchestration.<\/li>\n<li><strong>Matching service:<\/strong> Matches workflow or activity tasks with workers ready to complete them.<\/li>\n<li><strong>Internal worker service:<\/strong> Meets internal requirements (such as archiving) by introducing Cadence workflows and activities.<\/li>\n<li><strong>Workers:<\/strong> Function as Cadence client apps that execute user-created workflow and activity logic.<\/li>\n<\/ul>\n<p>By default, Cadence supports Apache Cassandra, MySQL, PostgreSQL, CockroachDB, and TiDB for use as persistence stores, as well as ElasticSearch and OpenSearch for listing workflows with complex predicates.<\/p>\n<\/p>\n<div class=\"embedded-resource-list callout-float-right\">\n<div class=\"field field--name-title field--type-string field--label-hidden field__item\">Programming and development<\/div>\n<div class=\"field field--name-links field--type-link field--label-hidden field__items\">\n<div class=\"field__item\"><a href=\"https:\/\/developers.redhat.com\/?intcmp=7016000000127cYAAQ\">Red Hat Developers Blog<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/downloads\/cheat-sheets?intcmp=7016000000127cYAAQ\">Programming cheat sheets<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/www.redhat.com\/en\/services\/training\/learning-subscription?intcmp=7016000000127cYAAQ\">Try for free: Red Hat Learning Subscription<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/downloads\/bash-programming-guide?intcmp=7016000000127cYAAQ\">eBook: An introduction to programming with Bash<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/developers.redhat.com\/cheat-sheets\/bash-shell-cheat-sheet?intcmp=7016000000127cYAAQ\">Bash shell scripting cheat sheet<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/developers.redhat.com\/e-books\/modernizing-enterprise-java?intcmp=7016000000127cYAAQ\">eBook: Modernizing Enterprise Java<\/a><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<p>Because the Cadence service is multi-tenant, a single service can serve one or many applications. A local Cadence service instance can be configured with docker-compose for local development. The Cadence service maintains workflow states, associated durable timers, and internal &#8220;task list&#8221; queues to send tasks to external workers.<\/p>\n<p>Beyond the Cadence service itself:<\/p>\n<ul>\n<li>\n<p><strong>Workflow workers<\/strong>: hosts fault-oblivious code externally to the Cadence service. The Cadence service sends these workers &#8220;decision tasks.&#8221; The workers deliver the tasks to the workflow code and communicate the completed &#8220;decisions&#8221; back to the Cadence service. Workflow code can be implemented in any language able to communicate with Cadence API: production-ready Java and Go clients are currently available.<\/p>\n<\/li>\n<li>\n<p><strong>Activity workers:<\/strong> hosts &#8220;activities&#8221;, or code that perform application specific actions such as service calls, database record updates, and file downloads. Activities feature task routing to specific processes, heartbeats, infinite retries, and unlimited execution time. The Cadence service sends activity tasks to these workers, who complete them and report completion.<\/p>\n<\/li>\n<li>\n<p><strong>External clients:<\/strong> enable the creation of workflow instances, or &#8220;executions&#8221;. External clients such as UIs, microservices or CLIs use the StartWorkflowExecution Cadence service API call to implement executions. External clients are also capable of notifying workflows about asynchronous external events, synchronous workflow state queries, waiting for synchronous workflow completion, workflow restarts, cancellation, and searching for specific workflows with List API.<\/p>\n<\/li>\n<\/ul>\n<h2>Getting started with Cadence<\/h2>\n<p>In this example we&#8217;ll use the Cadence Java client. The client is <a href=\"https:\/\/github.com\/uber\/cadence-java-client\">available from GitHub<\/a>, and <a href=\"https:\/\/www.javadoc.io\/doc\/com.uber.cadence\/cadence-client\/latest\/index.html\">JavaDoc documentation can be found here<\/a>. You can also check for the <a href=\"https:\/\/github.com\/uber\/cadence-java-client\/releases\">latest release version<\/a>.<\/p>\n<p>To begin, add <em>cadence-client<\/em> as a dependency to your <em>pom.xml<\/em> file like this:<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\"><span class=\"sy0\">dependency<span class=\"sy0\">&gt;<\/span><br><br><span class=\"sy0\">groupId<span class=\"sy0\">&gt;<\/span>com.uber.cadence<span class=\"sy0\"><\/span>groupId<span class=\"sy0\">&gt;<\/span><br><br><span class=\"sy0\">artifactId<span class=\"sy0\">&gt;<\/span>cadence-client<span class=\"sy0\"><\/span>artifactId<span class=\"sy0\">&gt;<\/span><br><br><span class=\"sy0\">version<span class=\"sy0\">&gt;<\/span>LATEST.RELEASE.VERSION<span class=\"sy0\"><\/span>version<span class=\"sy0\">&gt;<\/span><br><br><span class=\"sy0\"><\/span>dependency<span class=\"sy0\">&gt;<\/span><\/span><\/span><\/span><\/span><\/div><\/div><\/pre>\n<p>Alternatively, you can use <em>build.gradle<\/em>:<\/p>\n<p>compile group: \u2018com.uber.cadence&#8217;, name: \u2018cadence-client&#8217;, version: \u2018LATEST.RELEASE.VERSION&#8217;<\/p>\n<p><strong>Java Hello World with Cadence<\/strong><\/p>\n<p>The best way to get an idea of what Cadence is capable of is to try it, so here&#8217;s a simple &#8220;Hello World&#8221; example you can try. First, add the <a href=\"https:\/\/mvnrepository.com\/artifact\/com.uber.cadence\/cadence-client\">Cadence Java client dependency<\/a> to your Java project. Using Gradle, the dependency looks like this:<\/p>\n<p>compile group: \u2018com.uber.cadence&#8217;, name: \u2018cadence-client&#8217;, version: \u2018<latest_version>&#8216;<\/latest_version><\/p>\n<p>Add these dependencies that the cadence-client requires as well:<\/p>\n<p>compile group: \u2018commons-configuration&#8217;, name: \u2018commons-configuration&#8217;, version: \u20181.9&#8242;<\/p>\n<p>compile group: \u2018ch.qos.logback&#8217;, name: \u2018logback-classic&#8217;, version: \u20181.2.3&#8242;<\/p>\n<p>Then compile this code:<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\">import com.uber.cadence.workflow.Workflow;<br>\nimport com.uber.cadence.workflow.WorkflowMethod;<br>\nimport org.slf4j.Logger;<br>\npublic class GettingStarted <span class=\"br0\">{<\/span><br>\nprivate static Logger logger = Workflow.getLogger<span class=\"br0\">(<\/span>GettingStarted.class<span class=\"br0\">)<\/span>;<br>\npublic interface HelloWorld <span class=\"br0\">{<\/span><br><span class=\"sy0\">@<\/span>WorkflowMethod<br>\nvoid sayHello<span class=\"br0\">(<\/span>String name<span class=\"br0\">)<\/span>;<br><span class=\"br0\">}<\/span><br><span class=\"br0\">}<\/span><\/div><\/div><\/pre>\n<p>These <a href=\"https:\/\/github.com\/uber\/cadence-java-samples\">Cadence Java samples<\/a> are available to help if you encounter issues with the build files.<\/p>\n<p>Next, put this logback config file into your classpath:<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\"><span class=\"sy0\">configuration<span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\">appender <span class=\"re2\">name<\/span>=<span class=\"st0\">\"STDOUT\"<\/span> <span class=\"re2\">class<\/span>=<span class=\"st0\">\"ch.qos.logback.core.ConsoleAppender\"<\/span><span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\">-- encoders are assigned the <span class=\"kw3\">type<\/span><br>\nch.qos.logback.classic.encoder.PatternLayoutEncoder by default --<span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\">encoder<span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\">pattern<span class=\"sy0\">&gt;%<\/span>d<span class=\"br0\">{<\/span>HH:mm:ss.SSS<span class=\"br0\">}<\/span> <span class=\"br0\">[<\/span><span class=\"sy0\">%<\/span>thread<span class=\"br0\">]<\/span> <span class=\"sy0\">%<\/span>-5level <span class=\"sy0\">%<\/span>logger<span class=\"br0\">{<\/span><span class=\"nu0\">36<\/span><span class=\"br0\">}<\/span> - <span class=\"sy0\">%<\/span>msg<span class=\"sy0\">%<\/span>n<span class=\"sy0\"><\/span>pattern<span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\"><\/span>encoder<span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\"><\/span>appender<span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\">logger <span class=\"re2\">name<\/span>=<span class=\"st0\">\"io.netty\"<\/span> <span class=\"re2\">level<\/span>=<span class=\"st0\">\"INFO\"<\/span><span class=\"sy0\">\/&gt;<\/span><br><span class=\"sy0\">root <span class=\"re2\">level<\/span>=<span class=\"st0\">\"INFO\"<\/span><span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\">appender-ref <span class=\"re2\">ref<\/span>=<span class=\"st0\">\"STDOUT\"<\/span> <span class=\"sy0\">\/&gt;<\/span><br><span class=\"sy0\"><\/span>root<span class=\"sy0\">&gt;<\/span><br><span class=\"sy0\"><\/span>configuration<span class=\"sy0\">&gt;<\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/span><\/div><\/div><\/pre>\n<p>Now create the Hello World workflow. Add HelloWorldImpl with the sayHello method, which logs and returns &#8220;Hello \u2026&#8221;:<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\">import com.uber.cadence.worker.Worker;<br>\nimport com.uber.cadence.workflow.Workflow;<br>\nimport com.uber.cadence.workflow.WorkflowMethod;<br>\nimport org.slf4j.Logger;<br>\npublic class GettingStarted <span class=\"br0\">{<\/span><br>\nprivate static Logger logger = Workflow.getLogger<span class=\"br0\">(<\/span>GettingStarted.class<span class=\"br0\">)<\/span>;<br>\npublic interface HelloWorld <span class=\"br0\">{<\/span><br><span class=\"sy0\">@<\/span>WorkflowMethod<br>\nvoid sayHello<span class=\"br0\">(<\/span>String name<span class=\"br0\">)<\/span>;<br><span class=\"br0\">}<\/span><br>\npublic static class HelloWorldImpl implements HelloWorld <span class=\"br0\">{<\/span><br><span class=\"sy0\">@<\/span>Override<br>\npublic void sayHello<span class=\"br0\">(<\/span>String name<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span><br>\nlogger.info<span class=\"br0\">(<\/span><span class=\"st0\">\"Hello \"<\/span> + name + <span class=\"st0\">\"!\"<\/span><span class=\"br0\">)<\/span>;<br><span class=\"br0\">}<\/span><br><span class=\"br0\">}<\/span><br><span class=\"br0\">}<\/span><\/div><\/div><\/pre>\n<p>Register the workflow implementation to the Cadence framework with a worker connected to a Cadence service. Workers will connect to a Cadence service running locally by default.<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\">public static void main<span class=\"br0\">(<\/span>String<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span> args<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span><br>\nWorkflowClient workflowClient =<br>\nWorkflowClient.newInstance<span class=\"br0\">(<\/span><br>\nnew WorkflowServiceTChannel<span class=\"br0\">(<\/span>ClientOptions.defaultInstance<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"br0\">)<\/span>,<br>\nWorkflowClientOptions.newBuilder<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span>.setDomain<span class=\"br0\">(<\/span>DOMAIN<span class=\"br0\">)<\/span>.build<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"br0\">)<\/span>;<br><span class=\"sy0\">\/\/<\/span> Get worker to poll the task list.<br>\nWorkerFactory factory = WorkerFactory.newInstance<span class=\"br0\">(<\/span>workflowClient<span class=\"br0\">)<\/span>;<br>\nWorker worker = factory.newWorker<span class=\"br0\">(<\/span>TASK_LIST<span class=\"br0\">)<\/span>;<br>\nworker.registerWorkflowImplementationTypes<span class=\"br0\">(<\/span>HelloWorldImpl.class<span class=\"br0\">)<\/span>;<br>\nfactory.start<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span>;<br><span class=\"br0\">}<\/span><\/div><\/div><\/pre>\n<p>Now you&#8217;re ready to run the worker program. Here&#8217;s an example log:<\/p>\n<p>13:35:02.575 [main] INFO c.u.c.s.WorkflowServiceTChannel &#8211; Initialized TChannel for service cadence-frontend, LibraryVersion: 2.2.0, FeatureVersion: 1.0.0<\/p>\n<p>13:35:02.671 [main] INFO c.u.cadence.internal.worker.Poller &#8211; start(): Poller{options=PollerOptions{maximumPollRateIntervalMilliseconds=1000, maximumPollRatePerSecond=0.0, pollBackoffCoefficient=2.0, pollBackoffInitialInterval=PT0.2S, pollBackoffMaximumInterval=PT20S, pollThreadCount=1, pollThreadNamePrefix=\u2018Workflow Poller taskList=&#8221;HelloWorldTaskList&#8221;, domain=&#8221;test-domain&#8221;, type=&#8221;workflow&#8221;&#8216;}, identity=45937@maxim-C02XD0AAJGH6}<\/p>\n<p>13:35:02.673 [main] INFO c.u.cadence.internal.worker.Poller &#8211; start(): Poller{options=PollerOptions{maximumPollRateIntervalMilliseconds=1000, maximumPollRatePerSecond=0.0, pollBackoffCoefficient=2.0, pollBackoffInitialInterval=PT0.2S, pollBackoffMaximumInterval=PT20S, pollThreadCount=1, pollThreadNamePrefix=\u2018null&#8217;}, identity=81b8d0ac-ff89-47e8-b842-3dd26337feea}<\/p>\n<p>&#8220;Hello&#8221;&#8216;isn&#8217;t printing, because the worker only hosts the workflow code. To execute the workflow, start it with the Cadence CLI:<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\">$ docker run <span class=\"re5\">--network<\/span>=host <span class=\"re5\">--rm<\/span> ubercadence<span class=\"sy0\">\/<\/span>cli:master <span class=\"re5\">--do<\/span> test-domain workflow start <span class=\"re5\">--tasklist<\/span> HelloWorldTaskList --workflow_type HelloWorld::sayHello --execution_timeout <span class=\"nu0\">3600<\/span> <span class=\"re5\">--input<\/span> <span class=\"co3\">\"<\/span>World<span class=\"co3\">\"<\/span><br>\nStarted Workflow Id: bcacfabd-9f9a-46ac-9b25-83bcea5d7fd7, run Id: e7c40431-8e23-485b-<span class=\"nu0\">9649<\/span>-e8f161219efe<\/div><\/div><\/pre>\n<p>Now the program gives this output:<\/p>\n<p>13:35:02.575 [main] INFO c.u.c.s.WorkflowServiceTChannel &#8211; Initialized TChannel for service cadence-frontend, LibraryVersion: 2.2.0, FeatureVersion: 1.0.0<\/p>\n<p>13:35:02.671 [main] INFO c.u.cadence.internal.worker.Poller &#8211; start(): Poller{options=PollerOptions{maximumPollRateIntervalMilliseconds=1000, maximumPollRatePerSecond=0.0, pollBackoffCoefficient=2.0, pollBackoffInitialInterval=PT0.2S, pollBackoffMaximumInterval=PT20S, pollThreadCount=1, pollThreadNamePrefix=\u2018Workflow Poller taskList=&#8221;HelloWorldTaskList&#8221;, domain=\u201ctest-domain\u201d, type=&#8221;workflow&#8221;&#8216;}, identity=45937@maxim-C02XD0AAJGH6}<\/p>\n<p>13:35:02.673 [main] INFO c.u.cadence.internal.worker.Poller &#8211; start(): Poller{options=PollerOptions{maximumPollRateIntervalMilliseconds=1000, maximumPollRatePerSecond=0.0, pollBackoffCoefficient=2.0, pollBackoffInitialInterval=PT0.2S, pollBackoffMaximumInterval=PT20S, pollThreadCount=1, pollThreadNamePrefix=\u2018null&#8217;}, identity=81b8d0ac-ff89-47e8-b842-3dd26337feea}<\/p>\n<p>13:40:28.308 [workflow-root] INFO c.u.c.samples.hello.GettingStarted &#8211; Hello World!<\/p>\n<p>Success! Now run this workflow execution:<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\">$ docker run <span class=\"re5\">--network<\/span>=host <span class=\"re5\">--rm<\/span> ubercadence<span class=\"sy0\">\/<\/span>cli:master <span class=\"re5\">--do<\/span> test-domain workflow start <span class=\"re5\">--tasklist<\/span> HelloWorldTaskList --workflow_type HelloWorld::sayHello --execution_timeout <span class=\"nu0\">3600<\/span> <span class=\"re5\">--input<\/span> <span class=\"co3\">\"<\/span>Cadence<span class=\"co3\">\"<\/span><br><br>\nStarted Workflow Id: d2083532-9c68-49ab-90e1-d960175377a7, run Id: 331bfa04-834b-45a7-861e-bcb9f6ddae3e<\/div><\/div><\/pre>\n<p>You should get this output:<\/p>\n<p>13:35:02.575 [main] INFO c.u.c.s.WorkflowServiceTChannel &#8211; Initialized TChannel for service cadence-frontend, LibraryVersion: 2.2.0, FeatureVersion: 1.0.0<\/p>\n<p>13:35:02.671 [main] INFO c.u.cadence.internal.worker.Poller &#8211; start(): Poller{options=PollerOptions{maximumPollRateIntervalMilliseconds=1000, maximumPollRatePerSecond=0.0, pollBackoffCoefficient=2.0, pollBackoffInitialInterval=PT0.2S, pollBackoffMaximumInterval=PT20S, pollThreadCount=1, pollThreadNamePrefix=\u2018Workflow Poller taskList=&#8221;HelloWorldTaskList&#8221;, domain=&#8221;test-domain&#8221;, type=&#8221;workflow&#8221;&#8216;}, identity=45937@maxim-C02XD0AAJGH6}<\/p>\n<p>13:35:02.673 [main] INFO c.u.cadence.internal.worker.Poller &#8211; start(): Poller{options=PollerOptions{maximumPollRateIntervalMilliseconds=1000, maximumPollRatePerSecond=0.0, pollBackoffCoefficient=2.0, pollBackoffInitialInterval=PT0.2S, pollBackoffMaximumInterval=PT20S, pollThreadCount=1, pollThreadNamePrefix=\u2018null&#8217;}, identity=81b8d0ac-ff89-47e8-b842-3dd26337feea}<\/p>\n<p>13:40:28.308 [workflow-root] INFO c.u.c.samples.hello.GettingStarted &#8211; Hello World!<\/p>\n<p>13:42:34.994 [workflow-root] INFO c.u.c.samples.hello.GettingStarted &#8211; Hello Cadence!<\/p>\n<p>Lastly, use this CLI to list the workflow:<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\">$ docker run <span class=\"re5\">--network<\/span>=host <span class=\"re5\">--rm<\/span> ubercadence<span class=\"sy0\">\/<\/span>cli:master <span class=\"re5\">--do<\/span> test-domain workflow list<br><br>\nWORKFLOW TYPE <span class=\"sy0\">|<\/span> WORKFLOW ID <span class=\"sy0\">|<\/span> RUN ID <span class=\"sy0\">|<\/span> START TIME <span class=\"sy0\">|<\/span> EXECUTION TIME <span class=\"sy0\">|<\/span> END TIME<br><br>\nHelloWorld::sayHello <span class=\"sy0\">|<\/span> d2083532-9c68-49ab-90e1-d960175377a7 <span class=\"sy0\">|<\/span> 331bfa04-834b-45a7-861e-bcb9f6ddae3e <span class=\"sy0\">|<\/span> <span class=\"nu0\">20<\/span>:<span class=\"nu0\">42<\/span>:<span class=\"nu0\">34<\/span> <span class=\"sy0\">|<\/span> <span class=\"nu0\">20<\/span>:<span class=\"nu0\">42<\/span>:<span class=\"nu0\">34<\/span> <span class=\"sy0\">|<\/span> <span class=\"nu0\">20<\/span>:<span class=\"nu0\">42<\/span>:<span class=\"nu0\">35<\/span><br><br>\nHelloWorld::sayHello <span class=\"sy0\">|<\/span> bcacfabd-9f9a-46ac-9b25-83bcea5d7fd7 <span class=\"sy0\">|<\/span> e7c40431-8e23-485b-<span class=\"nu0\">9649<\/span>-e8f161219efe <span class=\"sy0\">|<\/span> <span class=\"nu0\">20<\/span>:<span class=\"nu0\">40<\/span>:<span class=\"nu0\">28<\/span> <span class=\"sy0\">|<\/span> <span class=\"nu0\">20<\/span>:<span class=\"nu0\">40<\/span>:<span class=\"nu0\">28<\/span> <span class=\"sy0\">|<\/span> <span class=\"nu0\">20<\/span>:<span class=\"nu0\">40<\/span>:<span class=\"nu0\">29<\/span><\/div><\/div><\/pre>\n<p>Look over the workflow execution history as well:<\/p>\n<pre>\n<div class=\"geshifilter\"><div class=\"bash geshifilter-bash\">$ docker run <span class=\"re5\">--network<\/span>=host <span class=\"re5\">--rm<\/span> ubercadence<span class=\"sy0\">\/<\/span>cli:master <span class=\"re5\">--do<\/span> test-domain workflow showid 1965109f-607f-4b14-a5f2-24399a7b8fa7<br><span class=\"nu0\">1<\/span> WorkflowExecutionStarted <span class=\"br0\">{<\/span>WorkflowType:<span class=\"br0\">{<\/span>Name:HelloWorld::sayHello<span class=\"br0\">}<\/span>,<br>\nTaskList:<span class=\"br0\">{<\/span>Name:HelloWorldTaskList<span class=\"br0\">}<\/span>,<br>\nInput:<span class=\"br0\">[<\/span><span class=\"st0\">\"World\"<\/span><span class=\"br0\">]<\/span>,<br>\nExecutionStartToCloseTimeoutSeconds:<span class=\"nu0\">3600<\/span>,<br>\nTaskStartToCloseTimeoutSeconds:<span class=\"nu0\">10<\/span>,<br>\nContinuedFailureDetails:<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span>,<br>\nLastCompletionResult:<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span>,<br>\nIdentity:cadence-cli<span class=\"sy0\">@<\/span>linuxkit-025000000001,<br>\nAttempt:<span class=\"nu0\">0<\/span>,<br>\nFirstDecisionTaskBackoffSeconds:<span class=\"nu0\">0<\/span><span class=\"br0\">}<\/span><br><span class=\"nu0\">2<\/span> DecisionTaskScheduled <span class=\"br0\">{<\/span>TaskList:<span class=\"br0\">{<\/span>Name:HelloWorldTaskList<span class=\"br0\">}<\/span>,<br>\nStartToCloseTimeoutSeconds:<span class=\"nu0\">10<\/span>,<br>\nAttempt:<span class=\"nu0\">0<\/span><span class=\"br0\">}<\/span><br><span class=\"nu0\">3<\/span> DecisionTaskStarted <span class=\"br0\">{<\/span>ScheduledEventId:<span class=\"nu0\">2<\/span>,<br>\nIdentity:<span class=\"nu0\">45937<\/span><span class=\"sy0\">@<\/span>maxim-C02XD0AAJGH6,<br>\nRequestId:481a14e5-67a4-436e-9a23-7f7fb7f87ef3<span class=\"br0\">}<\/span><br><span class=\"nu0\">4<\/span> DecisionTaskCompleted <span class=\"br0\">{<\/span>ExecutionContext:<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span>,<br>\nScheduledEventId:<span class=\"nu0\">2<\/span>,<br>\nStartedEventId:<span class=\"nu0\">3<\/span>,<br>\nIdentity:<span class=\"nu0\">45937<\/span><span class=\"sy0\">@<\/span>maxim-C02XD0AAJGH6<span class=\"br0\">}<\/span><br><span class=\"nu0\">5<\/span> WorkflowExecutionCompleted <span class=\"br0\">{<\/span>Result:<span class=\"br0\">[<\/span><span class=\"br0\">]<\/span>,<br>\nDecisionTaskCompletedEventId:<span class=\"nu0\">4<\/span><span class=\"br0\">}<\/span><\/div><\/div><\/pre>\n<p>It may be a simple workflow, but looking at the history is quite informative. The history&#8217;s value as a troubleshooting, analytics, and compliance tool only increases with the complexity of the workflow. As a best practice, automatically archive the history to a long-term blob store when workflows complete.<\/p>\n<h2>Try Cadence<\/h2>\n<p>Cadence offers transformative advantages for organizations and application development teams charged with creating and managing high-scale distributed applications built for high durability, availability, and scalability. Cadence is available to all as free and open source software, making it simple for teams to explore its capabilities and determine if Cadence is a strong fit for their organizations.<\/p>\n<p>Using Cadence is as simple as cloning the <a href=\"https:\/\/github.com\/uber\/cadence\">Git repository for the Cadence server<\/a> or the <a href=\"https:\/\/hub.docker.com\/r\/ubercadence\/server\">container image<\/a>. For more details on getting started, visit: <a href=\"https:\/\/cadenceworkflow.io\/docs\/get-started\/\">https:\/\/cadenceworkflow.io\/docs\/get-started\/<\/a>.<\/p>\n<\/div>\n<div class=\"clearfix text-formatted field field--name-field-article-subhead field--type-text-long field--label-hidden field__item\">\n<p>Cadence simplifies the complexity of distributed systems so that developers can focus on creating applications built for high durability, availability, and scalability.<\/p>\n<\/div>\n<div class=\"field field--name-field-lead-image field--type-entity-reference field--label-hidden field__item\">\n<article class=\"media media--type-image media--view-mode-caption\">\n<div class=\"field field--name-field-media-image field--type-image field--label-hidden field__item\">  <img decoding=\"async\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2022\/06\/gears_devops_learn_troubleshooting_lightbulb_tips_520.png\" width=\"520\" height=\"292\" alt=\"Tips and gears turning\" title=\"Tips and gears turning\" loading=\"lazy\"><\/div>\n<div class=\"field field--name-field-caption field--type-text-long field--label-hidden caption field__item\"><span class=\"caption__byline\">Image by: <\/span><\/p>\n<p>opensource.com<\/p>\n<\/div>\n<\/article>\n<\/div>\n<div class=\"field field--name-field-tags field--type-entity-reference field--label-hidden field__items\">\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/tags\/programming\" hreflang=\"en\">Programming<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/tags\/devops\" hreflang=\"en\">DevOps<\/a><\/div>\n<div class=\"field__item\"><a href=\"https:\/\/opensource.com\/tags\/alternatives\" hreflang=\"en\">Alternatives<\/a><\/div>\n<\/p><\/div>\n<div class=\"hidden field field--name-field-listicle-title field--type-string field--label-hidden field__item\">What to read next<\/div>\n<div class=\"field field--name-field-default-license field--type-list-string field--label-hidden field__item\"><a rel=\"license\" href=\"http:\/\/creativecommons.org\/licenses\/by-sa\/4.0\/\"><br \/>\n        <img decoding=\"async\" alt=\"Creative Commons License\" src=\"https:\/\/www.cryptocabaret.com\/wp-content\/uploads\/2022\/06\/cc-by-sa-4-3.png\" title=\"This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.\"><\/a>This work is licensed under a Creative Commons Attribution-Share Alike 4.0 International License.<\/div>\n<section class=\"field field--name-field-comments field--type-comment field--label-hidden comment-wrapper\">\n<div class=\"comments__count\">\n<div class=\"login\"><a href=\"https:\/\/opensource.com\/user\/register?absolute=1\">Register<\/a> or <a href=\"https:\/\/opensource.com\/user\/login?current=\/rss.xml&amp;absolute=1\">Login<\/a> to post a comment.<\/div>\n<\/p><\/div>\n<\/section>\n<p class=\"wpematico_credit\"><small>Powered by <a href=\"http:\/\/www.wpematico.com\" target=\"_blank\" rel=\"noopener\">WPeMatico<\/a><\/small><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Get started with Cadence, an open source workflow engine Ben Slater Thu, 06\/02\/2022 &#8211; 03:00 Register or Login to like Register or Login to like Modern applications require complicated interactions between long-running business processes, internal services, and third-party APIs. To say it&#8217;s been a challenge for developers is putting it mildly. Managing these processes means [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":64789,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[307],"tags":[],"class_list":["post-64788","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-open-source"],"_links":{"self":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts\/64788","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=64788"}],"version-history":[{"count":0,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/posts\/64788\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=\/wp\/v2\/media\/64789"}],"wp:attachment":[{"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=64788"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=64788"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.cryptocabaret.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=64788"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}