{"id":82515,"date":"2018-10-08T07:00:02","date_gmt":"2018-10-08T04:00:02","guid":{"rendered":"https:\/\/www.javacodegeeks.com\/?p=82515"},"modified":"2018-10-07T19:39:57","modified_gmt":"2018-10-07T16:39:57","slug":"starting-flows-trackby","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html","title":{"rendered":"Starting Flows with trackBy"},"content":{"rendered":"<p>Still continuing my trend of looking at Corda Services, I have some more tips to help your CorDapp work smoothly. This time around, we will focus on using trackBy to initiate Flows from inside a Service and the discrete problem that can arise if you are not careful.<\/p>\n<p>This should be a relatively short post as I can lean upon the work in my previous posts: <a href=\"https:\/\/www.javacodegeeks.com\/2018\/08\/corda-services-101.html\" target=\"_blank\" rel=\"noopener\">Corda Services 101<\/a> and <a href=\"https:\/\/www.javacodegeeks.com\/2018\/09\/asynchronous-flow-invocations-corda-services.html\" target=\"_blank\" rel=\"noopener\">Asynchronous Flow invocations with Corda Services<\/a>. The content found in <a href=\"https:\/\/www.javacodegeeks.com\/2018\/09\/asynchronous-flow-invocations-corda-services.html\" target=\"_blank\" rel=\"noopener\">Asynchronous Flow invocations with Corda Services<\/a> is very relevant to this post and will contain extra information not included within this post.<\/p>\n<p>This post is applicable to both Corda Open Source and Enterprise. The versions at the time of writing are Open Source <code>3.2<\/code> and Enterprise <code>3.1<\/code>.<\/p>\n<h3>A brief introduction to trackBy<\/h3>\n<p><code>trackBy<\/code> allows you to write code that executes when a transaction containing states of a specified type completes. Whether they are included as inputs or outputs, the code will still trigger.<\/p>\n<p>From here, you can decide what you want it to do. Maybe something very simple, like logging that a state has been received. Or, maybe something more interesting, such as initiating a new Flow. This use-case makes perfect sense for this feature. Once a node receives a new state or consumes one, they can start a new Flow that represents the next logical step in a workflow.<\/p>\n<p>Furthermore, there are two versions of <code>trackBy<\/code>. One, the <code>trackBy<\/code> I keep mentioning, that can be used within a CorDapp. The other, <code>vaultTrackBy<\/code>, is called from outside of the node using RPC.<\/p>\n<p>The problems presented in this post are only present in the CorDapp version, <code>trackBy<\/code>. Therefore, we will exclude <code>vaultTrackBy<\/code> for the remainder of this post.<\/p>\n<h3>What is this discrete problem?<\/h3>\n<p>Deadlock. When I word it that way, it isn\u2019t very discrete. But, the way it happens is rather subtle and requires a good understanding of what is going on to figure it out. As mentioned before, this issue is very similar to the one detailed in <a href=\"https:\/\/www.javacodegeeks.com\/2018\/09\/asynchronous-flow-invocations-corda-services.html\" target=\"_blank\" rel=\"noopener\">Asynchronous Flow invocations with Corda Services<\/a>. Furthermore, another shoutout to R3 for diagnosing this problem when I faced it in a project and I am sure they are going to iron this out. Until then, this post should save you some head scratching in case you run into the same problem.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<p>I will quote what I wrote in my previous post as its explanation is only missing one point in regards to this post.<\/p>\n<p><em>\u201cThe Flow Worker queue looks after the order that Flows execute in and will fill and empty as Flows are added and completed. This queue is crucial in coordinating the execution of Flows within a node. It is also the source of pain when it comes to multi-threading Flows ourselves.\u201d<\/em><\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82526\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue.png\" alt=\"trackBy\" width=\"820\" height=\"317\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue.png 925w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue-300x116.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue-768x297.png 768w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p><em>\u201cWhy am I talking about this queue? Well, we need to be extra careful not to fill the queue up with Flows that cannot complete.<\/em><\/p>\n<p><em>How can that happen? By starting a Flow within an executing Flow who then awaits its finish. This won\u2019t cause a problem until all the threads in the queue\u2019s thread pool encounter this situation. Once it does happen, it leaves the queue in deadlock. No Flows can finish, as they all rely on a number of queued Flows to complete.\u201d<\/em><\/p>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue-deadlock.png\"><img decoding=\"async\" class=\"aligncenter wp-image-82527\" src=\"http:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue-deadlock.png\" alt=\"trackBy\" width=\"820\" height=\"108\" srcset=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue-deadlock.png 925w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue-deadlock-300x40.png 300w, https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/10\/corda-flow-queue-deadlock-768x101.png 768w\" sizes=\"(max-width: 820px) 100vw, 820px\" \/><\/a><\/p>\n<p>That marks the end of my copypasta. I am going to keep saying this though, really, I suggest you read through <a href=\"https:\/\/www.javacodegeeks.com\/2018\/09\/asynchronous-flow-invocations-corda-services.html\" target=\"_blank\" rel=\"noopener\">Asynchronous Flow invocations with Corda Services<\/a> for a thorough explanation into this subject.<\/p>\n<p>What has this got to do with <code>trackBy<\/code>? Calling <code>trackBy<\/code> from a Service will run each observable event on a Flow Worker thread. In other words, each event takes up a spot on the queue. Starting a Flow from here will add another item to the queue and suspend the current thread until the Flow finishes. It will stay in the queue until that time. If you end up in a situation where all the spots on the queue are held by the observable events, rather than actual Flows, I got one word for you. Deadlock. It is the exact same situation I\u2019ve detailed before but starting from a different epicenter.<\/p>\n<p>On the bright side, the solution is a piece of cake (where did this saying come from anyway?).<\/p>\n<h3>The section where the problem is fixed<\/h3>\n<p>Now that you know what the problem is. Altering a \u201cbroken\u201d version to one shielded from deadlock will only require a few extra lines.<\/p>\n<p>Let\u2019s take a look at some code that is very similar to what lead me to step onto this landmine:<\/p>\n<p>This Service uses <code>trackBy<\/code> to start a new Flow whenever the node receives new <code>MessageState<\/code>s. For all the reasons mentioned previously, this code has the potential to deadlock. We don\u2019t know when, or if it will ever happen. But, it could. So we should probably sort it out before it is an issue.<\/p>\n<p>The code below will do just that:<\/p>\n<p>I have added a few comments to make it clearer what changed since only a few lines were added.<\/p>\n<p>All this change does, is start the Flow on a new thread. This then allows the current thread to end. Remember, this is important because this thread holds onto a position in the queue. Allowing it to end, frees up a slot for whatever comes next. Whether it is another observable event from <code>trackBy<\/code> or a Flow. It does not matter. As long as the thread is released, the possibility of deadlock occurring due to this code is naught.<\/p>\n<h3>Releasing you from this thread<\/h3>\n<p>Please take a moment to bask in the glory of the pun I made in this sections header. Maybe it\u2019s not that good, but I\u2019m still proud of it.<\/p>\n<p>In conclusion, using <code>trackBy<\/code> in a Corda Service is perfect for starting off new processes based on information being saved to the node. But, you need to be careful when starting new Flows from a <code>trackBy<\/code> observable. This is due to the observable holding onto a Flow Worker thread and therefore a spot in the queue. If your throughput reaches higher numbers, you risk the chance of your node deadlocking. You could end up in a situation where the queue is blocked by threads that are all waiting for a Flow to finish but with no actual Flows in the queue. By moving the Flow invocations onto a separate thread from the observable thread. You allow the once held spot on the queue to be released. There is now no chance of your <code>trackBy<\/code> code causing deadlock.<\/p>\n<p>The code used in this post can be found on my <a href=\"https:\/\/github.com\/lankydan\/corda-service-trackby-flows\" target=\"_blank\" rel=\"noopener\">GitHub<\/a>.<\/p>\n<p>If you found this post helpful, you can follow me on Twitter at <a href=\"http:\/\/www.twitter.com\/LankyDanDev\" target=\"_blank\" rel=\"noopener\">@LankyDanDev<\/a> to keep up with my new posts.<\/p>\n<div class=\"attribution\">\n<table>\n<tbody>\n<tr>\n<td>Published on Java Code Geeks with permission by Dan Newton, partner at our <a href=\"\/\/www.javacodegeeks.com\/join-us\/jcg\/\" target=\"_blank\" rel=\"noopener\">JCG program<\/a>. See the original article here: <a href=\"https:\/\/lankydanblog.com\/2018\/10\/05\/starting-flows-with-trackby\/\" target=\"_blank\" rel=\"noopener\">Starting Flows with trackBy<\/a><\/p>\n<p>Opinions expressed by Java Code Geeks contributors are their own.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Still continuing my trend of looking at Corda Services, I have some more tips to help your CorDapp work smoothly. This time around, we will focus on using trackBy to initiate Flows from inside a Service and the discrete problem that can arise if you are not careful. This should be a relatively short post &hellip;<\/p>\n","protected":false},"author":12894,"featured_media":80937,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[8],"tags":[1646,1760,1208],"class_list":["post-82515","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-enterprise-java","tag-blockchain","tag-corda","tag-kotlin"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Starting Flows with trackBy - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"Interested to learn more about trackby? Check our article explaining how to initiate flows using trackby from inside a Service.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Starting Flows with trackBy - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"Interested to learn more about trackby? Check our article explaining how to initiate flows using trackby from inside a Service.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2018-10-08T04:00:02+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/07\/corda-logo.png\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dan Newton\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@LankyDanDev\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dan Newton\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html\"},\"author\":{\"name\":\"Dan Newton\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/00ad664c44d777ebfa4d984dcf2717e2\"},\"headline\":\"Starting Flows with trackBy\",\"datePublished\":\"2018-10-08T04:00:02+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html\"},\"wordCount\":1153,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2018\\\/07\\\/corda-logo.png\",\"keywords\":[\"Blockchain\",\"Corda\",\"Kotlin\"],\"articleSection\":[\"Enterprise Java\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html\",\"name\":\"Starting Flows with trackBy - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2018\\\/07\\\/corda-logo.png\",\"datePublished\":\"2018-10-08T04:00:02+00:00\",\"description\":\"Interested to learn more about trackby? Check our article explaining how to initiate flows using trackby from inside a Service.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2018\\\/07\\\/corda-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2018\\\/07\\\/corda-logo.png\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2018\\\/10\\\/starting-flows-trackby.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Enterprise Java\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/java\\\/enterprise-java\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Starting Flows with trackBy\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/00ad664c44d777ebfa4d984dcf2717e2\",\"name\":\"Dan Newton\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g\",\"caption\":\"Dan Newton\"},\"sameAs\":[\"https:\\\/\\\/lankydanblog.com\\\/\",\"https:\\\/\\\/www.linkedin.com\\\/in\\\/danknewton\\\/\",\"https:\\\/\\\/x.com\\\/LankyDanDev\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/dan-newton\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Starting Flows with trackBy - Java Code Geeks","description":"Interested to learn more about trackby? Check our article explaining how to initiate flows using trackby from inside a Service.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html","og_locale":"en_US","og_type":"article","og_title":"Starting Flows with trackBy - Java Code Geeks","og_description":"Interested to learn more about trackby? Check our article explaining how to initiate flows using trackby from inside a Service.","og_url":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2018-10-08T04:00:02+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/07\/corda-logo.png","type":"image\/png"}],"author":"Dan Newton","twitter_card":"summary_large_image","twitter_creator":"@LankyDanDev","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Dan Newton","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html"},"author":{"name":"Dan Newton","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/00ad664c44d777ebfa4d984dcf2717e2"},"headline":"Starting Flows with trackBy","datePublished":"2018-10-08T04:00:02+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html"},"wordCount":1153,"commentCount":0,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/07\/corda-logo.png","keywords":["Blockchain","Corda","Kotlin"],"articleSection":["Enterprise Java"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html","url":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html","name":"Starting Flows with trackBy - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/07\/corda-logo.png","datePublished":"2018-10-08T04:00:02+00:00","description":"Interested to learn more about trackby? Check our article explaining how to initiate flows using trackby from inside a Service.","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/07\/corda-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2018\/07\/corda-logo.png","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2018\/10\/starting-flows-trackby.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"Java","item":"https:\/\/www.javacodegeeks.com\/category\/java"},{"@type":"ListItem","position":3,"name":"Enterprise Java","item":"https:\/\/www.javacodegeeks.com\/category\/java\/enterprise-java"},{"@type":"ListItem","position":4,"name":"Starting Flows with trackBy"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/00ad664c44d777ebfa4d984dcf2717e2","name":"Dan Newton","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b5024a6405bf07e14dacc299779fc0abded33b42a05190784776429e2c76435f?s=96&d=mm&r=g","caption":"Dan Newton"},"sameAs":["https:\/\/lankydanblog.com\/","https:\/\/www.linkedin.com\/in\/danknewton\/","https:\/\/x.com\/LankyDanDev"],"url":"https:\/\/www.javacodegeeks.com\/author\/dan-newton"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/82515","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/12894"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=82515"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/82515\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/80937"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=82515"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=82515"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=82515"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}