{"id":1341,"date":"2019-12-31T00:00:27","date_gmt":"2019-12-31T00:00:27","guid":{"rendered":"http:\/\/blog.softwareclues.com\/?p=1341"},"modified":"2020-10-10T19:30:39","modified_gmt":"2020-10-10T19:30:39","slug":"generic-asynchronous-retry-architecture","status":"publish","type":"post","link":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture","title":{"rendered":"Generic Asynchronous Retry Architecture"},"content":{"rendered":"<p id=\"54ba\" class=\"uo up so op b kf uq ur us ki ut uu uv uw ux uy uz va vb vc vd ve vf vg vh vi qr hc\" data-selectable-paragraph=\"\">Murphy\u2019s law says:<\/p>\n<blockquote class=\"vj vk vl\">\n<p id=\"b525\" class=\"uo up vm op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">Whatever can go wrong, will go wrong.<\/p>\n<\/blockquote>\n<p id=\"7cb4\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">It\u2019s so true in software engineering.<\/p>\n<p id=\"71d6\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">To build resilient software applications, when architecting the integration points with downstream services, we shall consider all error scenarios. Robust error handling is essential. Retrying remote API calls is an important part.<\/p>\n<p id=\"c94c\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">A retry can be done either synchronously or asynchronously. If the clients require a response of the execution status, not just the acknowledgement of the receipt of the request, it\u2019s appropriate to implement synchronous retries with limits on total retry numbers and time. On the other hand, if the clients don\u2019t care about the actual execution status, or have ways to receive responses asynchronously, it is almost always a good idea to adopt asynchronous retry architecture. Of course, before putting a request into asynchronous retry process, we can always implement synchronous retry first whenever it makes sense.<\/p>\n<p id=\"1a10\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">In this article, we will focus on the asynchronous retry architecture.<\/p>\n<h1 id=\"33c9\" class=\"tw tx so er es ty tz ua ub uc ud ue uf ug uh ui uj uk ul um un hc\" data-selectable-paragraph=\"\"><strong class=\"fw\">2. Queuing for Asynchronous Retry Architecture<\/strong><\/h1>\n<p id=\"452d\" class=\"uo up so op b kf uq ur us ki ut uu uv uw ux uy uz va vb vc vd ve vf vg vh vi qr hc\" data-selectable-paragraph=\"\">Queuing mechanism is the center of the Asynchronous Retry Architecture.<\/p>\n<p id=\"5d15\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">The originating service constructs a <strong class=\"op iz\">Retry Message<\/strong> that includes the original request info, the destination URL and other metadata, puts the <strong class=\"op iz\">Retry Message<\/strong> into an <strong class=\"op iz\">Async Retry Queue<\/strong> based on the chosen queuing system. A trigger could be configured in the queue to trigger a processor. Or, an <strong class=\"op iz\">Async Retry Processor<\/strong> can pull the queuing system for new messages. The <strong class=\"op iz\">Async Retry Processor<\/strong> can then utilize the message received from the <strong class=\"op iz\">Async Retry Queue<\/strong> and make another call to the destination downstream service.<\/p>\n<p id=\"f628\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">A <strong class=\"op iz\">Dead Letter Queue<\/strong> is used to hold <strong class=\"op iz\">Retry Message<\/strong>s for certain period time after a (configurable) maximum number of retries have been reached.<\/p>\n<p id=\"03a8\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">The below figure is a very high level workflow and message flow:<\/p>\n<h1 id=\"1ce3\" class=\"tw tx so er es ty tz ua ub uc ud ue uf ug uh ui uj uk ul um un hc\" data-selectable-paragraph=\"\"><strong class=\"fw\">3. Asynchronous Retry Architecture Diagram<\/strong><\/h1>\n<figure id=\"attachment_1342\" aria-describedby=\"caption-attachment-1342\" style=\"width: 700px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"1342\" data-permalink=\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture\/attachment\/1\" data-orig-file=\"https:\/\/i0.wp.com\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png?fit=700%2C366\" data-orig-size=\"700,366\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"1\" data-image-description=\"\" data-image-caption=\"&lt;p&gt;Asynchronous Retry Architecture&lt;\/p&gt;\n\" data-medium-file=\"https:\/\/i0.wp.com\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png?fit=300%2C157\" data-large-file=\"https:\/\/i0.wp.com\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png?fit=700%2C366\" class=\"wp-image-1342 size-full\" src=\"https:\/\/i0.wp.com\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png?resize=700%2C366\" alt=\"\" width=\"700\" height=\"366\" srcset=\"https:\/\/i0.wp.com\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png?w=700 700w, https:\/\/i0.wp.com\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png?resize=300%2C157 300w\" sizes=\"(max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" data-recalc-dims=\"1\" \/><figcaption id=\"caption-attachment-1342\" class=\"wp-caption-text\">Asynchronous Retry Architecture<\/figcaption><\/figure>\n<p id=\"ca63\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">In the above diagram, <strong class=\"op iz\">Service A<\/strong> is the calling service and <strong class=\"op iz\">Service B<\/strong> is the destination downstream service. If the initial call in <strong class=\"op iz\">Step 1<\/strong> fails, <strong class=\"op iz\">Service A<\/strong> will put a <strong class=\"op iz\">Retry Message<\/strong> into the <strong class=\"op iz\">Async Retry Queue<\/strong>.<\/p>\n<p id=\"2409\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">Depends on what Queuing System is chosen, either a trigger can be configured in the <strong class=\"op iz\">Async Retry Queue<\/strong> to trigger the Processor (3.1), or a Processor can be configured to poll the <strong class=\"op iz\">Async Retry Queue<\/strong> (3.2). If AWS SQS is chosen as the queuing system, a Lambda function can be configured to trigger the processor when a new message arrives.<\/p>\n<p id=\"cd48\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">Once the <strong class=\"op iz\">Async Retry Processor<\/strong> receives the <strong class=\"op iz\">Retry Message<\/strong>, it can use the request info in the message to reconstruct the request, and send the request to the destination URL that is also included in the retry message.<\/p>\n<p id=\"828f\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">A <strong class=\"op iz\">Retry Message<\/strong> will be moved to the <strong class=\"op iz\">Dead Letter Queue<\/strong> if the maximum retry attempts have been reached as detected by the <strong class=\"op iz\">Async Retry Processor<\/strong> or the <strong class=\"op iz\">Async Retry Queue<\/strong>.<\/p>\n<h1 id=\"6588\" class=\"tw tx so er es ty tz ua ub uc ud ue uf ug uh ui uj uk ul um un hc\" data-selectable-paragraph=\"\"><strong class=\"fw\">4.<\/strong> <strong class=\"fw\">Generic Data Model for Retry Message<\/strong><\/h1>\n<p id=\"c8ff\" class=\"uo up so op b kf uq ur us ki ut uu uv uw ux uy uz va vb vc vd ve vf vg vh vi qr hc\" data-selectable-paragraph=\"\">A Retry Message can have a generic data model as below:<\/p>\n<pre class=\"vt vu vv vw vx wn wo qh\">&lt;span id=&quot;60ab&quot; class=&quot;hc wp tx so wq b gg wr ws x wt&quot; data-selectable-paragraph=&quot;&quot;&gt;{\r\n    &quot;request&quot;:{\r\n        &quot;url&quot;:&quot;http[s]:\/\/$host:$port\/$destitnation_endpoint_including_query_parameters&quot;,\r\n        &quot;method&quot;:&quot;GET|POST|PUT|DELETE|PATCH&quot;,         \r\n        &quot;payload&quot;:&quot;$json_string&quot;,\r\n        &quot;headers&quot;:[$headers_to_pass_to_the_target_service]\r\n    },\r\n    &quot;receivedCount&quot;: &quot;$number&quot;,\r\n    &quot;async-retry-queue&quot;:&quot;$async-retry-queue[optional]&quot;,\r\n    &quot;dead-letter-queue&quot;:&quot;$dead-letter-queue[optional]&quot;\r\n}&lt;\/span&gt;<\/pre>\n<p id=\"f949\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">With this generic data model design for <strong class=\"op iz\">Retry Message<\/strong>, an <strong class=\"op iz\">Async Retry Processor<\/strong> can be designed to process any <strong class=\"op iz\">Retry Message<\/strong> constructed by any originating services (<strong class=\"op iz\">Service A<\/strong>) to any destination services (<strong class=\"op iz\">Service B<\/strong>).<\/p>\n<h1 id=\"c4a5\" class=\"tw tx so er es ty tz ua ub uc ud ue uf ug uh ui uj uk ul um un hc\" data-selectable-paragraph=\"\"><strong class=\"fw\">5. Retryable Errors<\/strong><\/h1>\n<p id=\"02a1\" class=\"uo up so op b kf uq ur us ki ut uu uv uw ux uy uz va vb vc vd ve vf vg vh vi qr hc\" data-selectable-paragraph=\"\">Only non-functional errors are retryable. Below are some examples:<\/p>\n<p id=\"1429\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">a. No response at all;<\/p>\n<p id=\"1dfd\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">b. Temporary Network issue, usually <strong class=\"op iz\">5xx<\/strong> (http status) errors;<\/p>\n<p id=\"fa76\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">c. Request timeout: http status 408 errors;<\/p>\n<p id=\"3a23\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">d. Conflict: http status 409 errors;<\/p>\n<p id=\"8b00\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">e. Too many request: http status 429<\/p>\n<p id=\"3cfc\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">f. If there is a Retry-After header in the http response of the downstream service;<\/p>\n<p id=\"8fd9\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">h. Unauthorized: http status 401 errors with expired token error code\/message. These kind of errors usually require a new token. In this case, the Async Retry Processor is responsible for getting the proper token.<\/p>\n<h1 id=\"d35c\" class=\"tw tx so er es ty tz ua ub uc ud ue uf ug uh ui uj uk ul um un hc\" data-selectable-paragraph=\"\"><strong class=\"fw\">6. <\/strong>Conclusion<\/h1>\n<p id=\"fc64\" class=\"uo up so op b kf uq ur us ki ut uu uv uw ux uy uz va vb vc vd ve vf vg vh vi qr hc\" data-selectable-paragraph=\"\"><strong class=\"op iz\">Asynchronous Retry Architecture<\/strong> can be used to handle all retryable errors when the client is not expecting the execution result in the response of the call. It is extremely useful if a function may need to be tried many times for a long period of time.<\/p>\n<p id=\"47c2\" class=\"uo up so op b kf vn ur us ki vo uu uv uw vp uy uz va vq vc vd ve vr vg vh vi qr hc\" data-selectable-paragraph=\"\">The number of maximum retry attempts, the async retry queue name\/url, and the dead letter queue name\/url can all be configurable. The configurable values can make architecture flexible for many different applications.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Murphy\u2019s law says: Whatever can go wrong, will go wrong &hellip; <a href=\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture\" class=\"more-link\">\u7ee7\u7eed\u9605\u8bfb<span class=\"screen-reader-text\">\u201cGeneric Asynchronous Retry Architecture\u201d<\/span><\/a><\/p>\n","protected":false},"author":1097,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":true,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[3],"tags":[78,132,133],"translation":{"provider":"WPGlobus","version":"2.12.2","language":"zh","enabled_languages":["en","zh"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"zh":{"title":false,"content":false,"excerpt":false}}},"jetpack_publicize_connections":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v22.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Generic Asynchronous Retry Architecture - \u8f6f\u4ef6\u542f\u793a\u5f55<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Generic Asynchronous Retry Architecture - \u8f6f\u4ef6\u542f\u793a\u5f55\" \/>\n<meta property=\"og:url\" content=\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture\" \/>\n<meta property=\"og:site_name\" content=\"\u8f6f\u4ef6\u542f\u793a\u5f55\" \/>\n<meta property=\"article:published_time\" content=\"2019-12-31T00:00:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2020-10-10T19:30:39+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png\" \/>\n<meta name=\"author\" content=\"Liesheng Long\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"Liesheng Long\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture\",\"url\":\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture\",\"name\":\"Generic Asynchronous Retry Architecture - \u8f6f\u4ef6\u542f\u793a\u5f55\",\"isPartOf\":{\"@id\":\"http:\/\/blog.softwareclues.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#primaryimage\"},\"image\":{\"@id\":\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#primaryimage\"},\"thumbnailUrl\":\"http:\/\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png\",\"datePublished\":\"2019-12-31T00:00:27+00:00\",\"dateModified\":\"2020-10-10T19:30:39+00:00\",\"author\":{\"@id\":\"http:\/\/blog.softwareclues.com\/#\/schema\/person\/ff797d30c4d54be305f52ff52a33a9a4\"},\"breadcrumb\":{\"@id\":\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#primaryimage\",\"url\":\"http:\/\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png\",\"contentUrl\":\"http:\/\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"http:\/\/blog.softwareclues.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Generic Asynchronous Retry Architecture\"}]},{\"@type\":\"WebSite\",\"@id\":\"http:\/\/blog.softwareclues.com\/#website\",\"url\":\"http:\/\/blog.softwareclues.com\/\",\"name\":\"\u8f6f\u4ef6\u542f\u793a\u5f55\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"http:\/\/blog.softwareclues.com\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"http:\/\/blog.softwareclues.com\/#\/schema\/person\/ff797d30c4d54be305f52ff52a33a9a4\",\"name\":\"Liesheng Long\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"http:\/\/blog.softwareclues.com\/#\/schema\/person\/image\/\",\"url\":\"http:\/\/0.gravatar.com\/avatar\/67b0b2025216951440393e7d97d7999d?s=96&d=mystery&r=g\",\"contentUrl\":\"http:\/\/0.gravatar.com\/avatar\/67b0b2025216951440393e7d97d7999d?s=96&d=mystery&r=g\",\"caption\":\"Liesheng Long\"},\"url\":\"http:\/\/blog.softwareclues.com\/zh\/author\/liesheng\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Generic Asynchronous Retry Architecture - \u8f6f\u4ef6\u542f\u793a\u5f55","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":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture","og_locale":"zh_CN","og_type":"article","og_title":"Generic Asynchronous Retry Architecture - \u8f6f\u4ef6\u542f\u793a\u5f55","og_url":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture","og_site_name":"\u8f6f\u4ef6\u542f\u793a\u5f55","article_published_time":"2019-12-31T00:00:27+00:00","article_modified_time":"2020-10-10T19:30:39+00:00","og_image":[{"url":"http:\/\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png"}],"author":"Liesheng Long","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"Liesheng Long","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"4 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture","url":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture","name":"Generic Asynchronous Retry Architecture - \u8f6f\u4ef6\u542f\u793a\u5f55","isPartOf":{"@id":"http:\/\/blog.softwareclues.com\/#website"},"primaryImageOfPage":{"@id":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#primaryimage"},"image":{"@id":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#primaryimage"},"thumbnailUrl":"http:\/\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png","datePublished":"2019-12-31T00:00:27+00:00","dateModified":"2020-10-10T19:30:39+00:00","author":{"@id":"http:\/\/blog.softwareclues.com\/#\/schema\/person\/ff797d30c4d54be305f52ff52a33a9a4"},"breadcrumb":{"@id":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture"]}]},{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#primaryimage","url":"http:\/\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png","contentUrl":"http:\/\/blog.softwareclues.com\/wp-content\/uploads\/2020\/10\/1.png"},{"@type":"BreadcrumbList","@id":"http:\/\/blog.softwareclues.com\/zh\/generic-asynchronous-retry-architecture#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http:\/\/blog.softwareclues.com\/"},{"@type":"ListItem","position":2,"name":"Generic Asynchronous Retry Architecture"}]},{"@type":"WebSite","@id":"http:\/\/blog.softwareclues.com\/#website","url":"http:\/\/blog.softwareclues.com\/","name":"\u8f6f\u4ef6\u542f\u793a\u5f55","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"http:\/\/blog.softwareclues.com\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"zh-Hans"},{"@type":"Person","@id":"http:\/\/blog.softwareclues.com\/#\/schema\/person\/ff797d30c4d54be305f52ff52a33a9a4","name":"Liesheng Long","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"http:\/\/blog.softwareclues.com\/#\/schema\/person\/image\/","url":"http:\/\/0.gravatar.com\/avatar\/67b0b2025216951440393e7d97d7999d?s=96&d=mystery&r=g","contentUrl":"http:\/\/0.gravatar.com\/avatar\/67b0b2025216951440393e7d97d7999d?s=96&d=mystery&r=g","caption":"Liesheng Long"},"url":"http:\/\/blog.softwareclues.com\/zh\/author\/liesheng"}]}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/paLJfj-lD","jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/posts\/1341"}],"collection":[{"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/users\/1097"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/comments?post=1341"}],"version-history":[{"count":7,"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/posts\/1341\/revisions"}],"predecessor-version":[{"id":1348,"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/posts\/1341\/revisions\/1348"}],"wp:attachment":[{"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/media?parent=1341"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/categories?post=1341"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.softwareclues.com\/zh\/wp-json\/wp\/v2\/tags?post=1341"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}