{"id":32246,"date":"2021-05-25T16:38:26","date_gmt":"2021-05-25T16:38:26","guid":{"rendered":"https:\/\/streamhub.co.uk\/?p=32246"},"modified":"2021-11-03T16:43:46","modified_gmt":"2021-11-03T16:43:46","slug":"an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses","status":"publish","type":"post","link":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/","title":{"rendered":"How to build an Asynchronous layer over Snowflake"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Reading Time: <\/span> <span class=\"rt-time\"> 5<\/span> <span class=\"rt-label rt-postfix\">minutes<\/span><\/span><p>[et_pb_section fb_built=&#8221;1&#8243; _builder_version=&#8221;4.0.6&#8243; custom_padding=&#8221;1px||0px|||&#8221; da_disable_devices=&#8221;off|off|off&#8221; global_colors_info=&#8221;{}&#8221; da_is_popup=&#8221;off&#8221; da_exit_intent=&#8221;off&#8221; da_has_close=&#8221;on&#8221; da_alt_close=&#8221;off&#8221; da_dark_close=&#8221;off&#8221; da_not_modal=&#8221;on&#8221; da_is_singular=&#8221;off&#8221; da_with_loader=&#8221;off&#8221; da_has_shadow=&#8221;on&#8221;][et_pb_row _builder_version=&#8221;3.27.4&#8243; min_height=&#8221;46px&#8221; custom_margin=&#8221;7px|auto||auto||&#8221; custom_padding=&#8221;0px||20px|||&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;3.27.4&#8243; global_colors_info=&#8221;{}&#8221;][et_pb_blurb title=&#8221;@ET-DC@eyJkeW5hbWljIjp0cnVlLCJjb250ZW50IjoicG9zdF9kYXRlIiwic2V0dGluZ3MiOnsiYmVmb3JlIjoiIiwiYWZ0ZXIiOiIiLCJkYXRlX2Zvcm1hdCI6ImRlZmF1bHQiLCJjdXN0b21fZGF0ZV9mb3JtYXQiOiIifX0=@&#8221; use_icon=&#8221;on&#8221; font_icon=&#8221;%%128%%&#8221; icon_color=&#8221;#00ac69&#8243; icon_placement=&#8221;left&#8221; content_max_width=&#8221;1100px&#8221; use_icon_font_size=&#8221;on&#8221; icon_font_size=&#8221;16px&#8221; _builder_version=&#8221;4.0.6&#8243; _dynamic_attributes=&#8221;title&#8221; header_font=&#8221;Work Sans|600|||||||&#8221; header_text_align=&#8221;left&#8221; header_font_size=&#8221;14px&#8221; text_orientation=&#8221;center&#8221; min_height=&#8221;12px&#8221; custom_margin=&#8221;||0px|||&#8221; animation=&#8221;off&#8221; hover_enabled=&#8221;1&#8243; locked=&#8221;off&#8221; global_colors_info=&#8221;{}&#8221; icon_color__hover=&#8221;#00ac69&#8243; box_shadow_color__hover_enabled=&#8221;rgba(0,0,0,0.3)&#8221; box_shadow_color__hover=&#8221;rgba(0,0,0,0.3)&#8221; box_shadow_style__hover=&#8221;none&#8221; box_shadow_style__hover_enabled=&#8221;none&#8221; use_background_color_gradient__hover=&#8221;off&#8221; use_background_color_gradient__hover_enabled=&#8221;off&#8221; background_color_gradient_start__hover=&#8221;#2b87da&#8221; background_color_gradient_start__hover_enabled=&#8221;#2b87da&#8221; background_color_gradient_end__hover=&#8221;#29c4a9&#8243; background_color_gradient_end__hover_enabled=&#8221;#29c4a9&#8243; background_color_gradient_type__hover=&#8221;linear&#8221; background_color_gradient_type__hover_enabled=&#8221;linear&#8221; background_color_gradient_direction__hover=&#8221;180deg&#8221; background_color_gradient_direction__hover_enabled=&#8221;180deg&#8221; background_color_gradient_direction_radial__hover=&#8221;center&#8221; background_color_gradient_direction_radial__hover_enabled=&#8221;center&#8221; background_color_gradient_start_position__hover=&#8221;0%&#8221; background_color_gradient_start_position__hover_enabled=&#8221;0%&#8221; background_color_gradient_end_position__hover=&#8221;100%&#8221; background_color_gradient_end_position__hover_enabled=&#8221;100%&#8221; background_color_gradient_overlays_image__hover=&#8221;off&#8221; background_color_gradient_overlays_image__hover_enabled=&#8221;off&#8221; parallax__hover=&#8221;off&#8221; parallax__hover_enabled=&#8221;off&#8221; parallax_method__hover=&#8221;on&#8221; parallax_method__hover_enabled=&#8221;on&#8221; background_size__hover=&#8221;cover&#8221; background_size__hover_enabled=&#8221;cover&#8221; background_position__hover=&#8221;center&#8221; background_position__hover_enabled=&#8221;center&#8221; background_repeat__hover=&#8221;no-repeat&#8221; background_repeat__hover_enabled=&#8221;no-repeat&#8221; background_blend__hover=&#8221;normal&#8221; background_blend__hover_enabled=&#8221;normal&#8221; allow_player_pause__hover=&#8221;off&#8221; allow_player_pause__hover_enabled=&#8221;off&#8221; background_video_pause_outside_viewport__hover=&#8221;on&#8221; background_video_pause_outside_viewport__hover_enabled=&#8221;on&#8221; body_letter_spacing__hover=&#8221;0px&#8221; body_letter_spacing__hover_enabled=&#8221;0px&#8221; body_text_shadow_style__hover=&#8221;none&#8221; body_text_shadow_style__hover_enabled=&#8221;none&#8221; body_text_shadow_color__hover=&#8221;rgba(0,0,0,0.4)&#8221; body_text_shadow_color__hover_enabled=&#8221;rgba(0,0,0,0.4)&#8221;][\/et_pb_blurb][\/et_pb_column][\/et_pb_row][\/et_pb_section][et_pb_section fb_built=&#8221;1&#8243; admin_label=&#8221;Services&#8221; _builder_version=&#8221;4.9.2&#8243; max_width=&#8221;90%&#8221; custom_padding=&#8221;0px||0px|||&#8221; da_disable_devices=&#8221;off|off|off&#8221; locked=&#8221;off&#8221; global_colors_info=&#8221;{}&#8221; da_is_popup=&#8221;off&#8221; da_exit_intent=&#8221;off&#8221; da_has_close=&#8221;on&#8221; da_alt_close=&#8221;off&#8221; da_dark_close=&#8221;off&#8221; da_not_modal=&#8221;on&#8221; da_is_singular=&#8221;off&#8221; da_with_loader=&#8221;off&#8221; da_has_shadow=&#8221;on&#8221;][et_pb_row _builder_version=&#8221;4.0.6&#8243; min_height=&#8221;58px&#8221; custom_padding=&#8221;4px|||||&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;4.0.6&#8243; global_colors_info=&#8221;{}&#8221;][et_pb_divider color=&#8221;#003387&#8243; divider_weight=&#8221;5px&#8221; _builder_version=&#8221;4.0.6&#8243; global_colors_info=&#8221;{}&#8221;][\/et_pb_divider][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;4.0.6&#8243; custom_margin=&#8221;-28px|auto||auto||&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;4.0.6&#8243; global_colors_info=&#8221;{}&#8221;][et_pb_text _builder_version=&#8221;4.9.2&#8243; custom_margin=&#8221;|-24px||||&#8221; custom_padding=&#8221;||11px|||&#8221; global_colors_info=&#8221;{}&#8221;]<\/p>\n<p><span style=\"font-family: inherit;\">Building an asynchronous solution for your analytic use-cases can be super powerful, especially building a deep-dive on-demand reporting solution. When we started building this at Streamhub, we found very little literature around this, so I am sharing this, hoping people pondering over this, can benefit from it. Our core analytical solution for such on-demand deep-dive use-cases is build upon Snowflake, based on design considerations listed in our <a href=\"https:\/\/streamhub.co.uk\/how-to-design-a-modern-data-analytics-platform\">previous <\/a>blog, and our asynchronous layer runs over this.<\/span><span style=\"font-family: inherit;\"><\/span><\/p>\n<p><span style=\"font-weight: 400;\"><\/span><\/p>\n<h4><b>What is an asynchronous service?<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Asynchronous service is one of the common methods of interacting with backend systems for processes which takes a long time to compute. Our async approach is based on polling and involves the 3 simple steps:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Execute <\/b><span style=\"font-weight: 400;\">the process asynchronously &amp; get the processId immediately.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Poll <\/b><span style=\"font-weight: 400;\">the status using the processId for every <\/span><i><span style=\"font-weight: 400;\">x<\/span><\/i><span style=\"font-weight: 400;\"> seconds until the process completes\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Return the <\/b><span style=\"font-weight: 400;\">response<\/span><\/li>\n<\/ol>\n<h4><b><\/b><\/h4>\n<h4><b><\/b><\/h4>\n<h4><b>How to achieve this?<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">There are a number of ways to implement Async in Snowflake. Here is the method we found to be most effective. It is based on polling, and we made full use of Snowflake&#8217;s information_schema.query_history.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\"><\/span><\/p>\n<h4><b>1. Executing an Async query<\/b><\/h4>\n<h4><span style=\"font-weight: 400;\">Scala and Python both have different ways of submitting an async query, Let&#8217;s look at both examples<\/span><\/h4>\n<p><b><\/b><\/p>\n<p><b>Scala:<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Once you get the connection string, using the preparedStatement you can unwrap the <\/span><span style=\"font-weight: 400;\">SnowflakePreparedStatement <\/span><span style=\"font-weight: 400;\">which<\/span> <span style=\"font-weight: 400;\">allows you to execute an Async query using executeAsyncQuery() method. Return the queryId back to the service which triggered the sql.<\/span><\/p>\n<table style=\"background-color: #f5f5f5;\">\n<tbody>\n<tr>\n<td>\n<pre><span style=\"color: #000000;\"><span style=\"color: #800080;\">def run(): (queryId, resultSet) = {\n val sqlString = \u201cSelect * from dual\u201d\n\u00a0val<\/span><span style=\"color: #800080;\"> conn<\/span> <span style=\"color: #993300;\">= getSnowflakeConnection()<\/span>\n\n\u00a0<span style=\"color: #800080;\">val<\/span> prep_statement = conn.prepareStatement(sqlString)\n\n <span style=\"color: #800080;\">val<\/span> (query_id, rs) = \n <span style=\"color: #800080;\">\/\/ run Async query<\/span>\n\u00a0<span style=\"color: #800080;\">if<\/span> (asyncRequest) {\n\u00a0 <span style=\"color: #800080;\">val<\/span> resultSet =\u00a0 prep_statement.unwrap(classOf<span style=\"color: #993300;\">[SnowflakePreparedStatement]<\/span>).executeAsyncQuery\n\u00a0 <span style=\"color: #800080;\">val<\/span> asyncQueryId = resultSet.unwrap(classOf<span style=\"color: #993300;\">[SnowflakeResultSet]<\/span>).getQueryID\n\u00a0 prep_statement.close()\n\u00a0 conn.close()\n\u00a0 (asyncQueryId, <span style=\"color: #993300;\">None<\/span>)\n } \n <span style=\"color: #800080;\">\/\/ run sync query<\/span>\n\u00a0else { \n\u00a0 <span style=\"color: #800080;\">val<\/span> resultSet = prep_statement.executeQuery\n\u00a0 <span style=\"color: #800080;\">val<\/span> queryId = resultSet.unwrap(classOf<span style=\"color: #993300;\">[SnowflakeResultSet]<\/span>).getQueryID\n\u00a0 (queryId, <span style=\"color: #993300;\">Some<\/span>(resultSet))\n }\n}<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: center;\"><b><i>Code: Submitting Async &amp; Sync queries to SF(Scala)<\/i><\/b><\/p>\n<p>&nbsp;<\/p>\n<p><b>Python:<\/b><\/p>\n<p><span style=\"font-weight: 400;\">It is straightforward in python, just passing the param<\/span> <span style=\"font-weight: 400;\">_no_results=<\/span><span style=\"font-weight: 400;\">True<\/span> <span style=\"font-weight: 400;\">will submit an async query<\/span><\/p>\n<table style=\"background-color: #f5f5f5;\">\n<tbody>\n<tr>\n<td>\n<pre><span>def run():<\/span>\n<span>\u00a0\u00a0sql_string = <\/span><span style=\"color: #339966;\">\"select * from dual\"<\/span><span>\n<\/span><span>\u00a0 cursor = get_snowflake_connection()<\/span><span>\n<\/span><span>\u00a0 <\/span><span style=\"color: #800080;\">if<\/span><span> async_request:<\/span><span>\n<\/span><span> \u00a0 \u00a0 cursor.execute(sql_string, _no_results=<\/span><span style=\"color: #993300;\">True<\/span><span>)<\/span><span>\n<\/span><span> \u00a0 \u00a0 query_id = cursor.sfqid<\/span><span>\n<\/span><span> \u00a0 \u00a0 <\/span><span style=\"color: #800080;\">return<\/span><span> query_id, None<\/span><span>\n<\/span><span>\u00a0 <\/span><span style=\"color: #800080;\">else<\/span><span>:<\/span><span>\n<\/span><span> \u00a0 \u00a0 cursor.execute(sql_string)<\/span><span>\n<\/span><span> \u00a0 \u00a0 result_set = cursor.fetchall()<\/span><span>\n<\/span><span> \u00a0 \u00a0 <\/span><span style=\"color: #800080;\">return<\/span><span> query_id, result_set<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: center;\"><b><i>Code: Submitting Async &amp; Sync queries to SF (Python)<\/i><\/b><\/p>\n<p style=\"text-align: center;\"><b><i><\/i><\/b><\/p>\n<h4><b>2. Polling for results\u00a0<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Let\u2019s poll the results, let&#8217;s say for every 5s using the queryId. Nice thing about Snowflake is that the history table provides the running status of the query in realtime and it is queryable as well as similar to any other table and it consumes a tiny amount of credits. This can be reduced by adding conditions in where clauses like warehouse, date etc to limit the search. I will leave that to you\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">So for every 5 s the below query will be used to check the status.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\"><\/span><\/p>\n<table style=\"background-color: #f5f5f5;\">\n<tbody>\n<tr>\n<td>\n<pre><span style=\"font-weight: 400; color: #339966;\">\"\"\"select query_id, execution_status, error_message from table(information_schema.query_history()) <\/span>\n<span style=\"font-weight: 400; color: #339966;\">\u00a0\u00a0\u00a0where query_id = '{0}'\"\"\"<\/span><span style=\"font-weight: 400;\">.format(query_id)<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: center;\"><b><i>Sql: to poll history table<\/i><\/b><\/p>\n<p style=\"text-align: center;\"><b><i><\/i><\/b><\/p>\n<p style=\"text-align: center;\"><b><i><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/UI.png\" width=\"383\" height=\"160\" alt=\"\" class=\"wp-image-32257 alignnone size-full\" srcset=\"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/UI.png 383w, https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/UI-300x125.png 300w\" sizes=\"auto, (max-width: 383px) 100vw, 383px\" \/><\/i><\/b><\/p>\n<p style=\"text-align: center;\"><b>Snowflake History UI<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Keep polling until the status is in running<\/span><\/p>\n<table style=\"background-color: #f5f5f5;\">\n<tbody>\n<tr>\n<td>\n<pre><span style=\"font-weight: 400; color: #800080;\">def<\/span> <span style=\"font-weight: 400; color: #0000ff;\">get_query_status<\/span><span style=\"font-weight: 400;\">(self, query_id):<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 sql = <\/span><span style=\"color: #339966;\"><span style=\"font-weight: 400;\">\"\"\"select query_id, execution_status, error_message from table (information_schema.query_history())<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 where query_id = '{0}'\"\"\"<\/span><\/span><span style=\"font-weight: 400;\">.format(query_id)<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">try<\/span><span style=\"font-weight: 400;\">:<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 self.cursor.execute(sql)<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 record = self.cursor.fetchone()<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">if<\/span><span style=\"font-weight: 400;\"> record is not <\/span><span style=\"font-weight: 400;\">None<\/span><span style=\"font-weight: 400;\">:<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 print(record)<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">if<\/span><span style=\"font-weight: 400;\"> record[<\/span><span style=\"font-weight: 400;\">1<\/span><span style=\"font-weight: 400;\">] == <\/span><span style=\"font-weight: 400;\">'<span style=\"color: #0000ff;\">FAILED_WITH_ERRO<\/span><\/span><span style=\"font-weight: 400;\"><span style=\"color: #0000ff;\">R<\/span>':<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">return<\/span> <span style=\"font-weight: 400;\">500<\/span><span style=\"font-weight: 400;\">, record[<\/span><span style=\"font-weight: 400;\">1<\/span><span style=\"font-weight: 400;\">], record[<\/span><span style=\"font-weight: 400;\">2<\/span><span style=\"font-weight: 400;\">]<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">else<\/span><span style=\"font-weight: 400;\">:<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">return<\/span> <span style=\"font-weight: 400;\">200<\/span><span style=\"font-weight: 400;\">, record[<\/span><span style=\"font-weight: 400;\">1<\/span><span style=\"font-weight: 400;\">], record[<\/span><span style=\"font-weight: 400;\">2<\/span><span style=\"font-weight: 400;\">]<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">else<\/span><span style=\"font-weight: 400;\">:<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">return<\/span> <span style=\"font-weight: 400;\">404<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"color: #339966;\"><span style=\"font-weight: 400;\">\"FAILED_WITH_ERROR\"<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">\"query_id Not found\"<\/span><span style=\"font-weight: 400;\">\n<\/span><\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 except snowflake.connector.errors.<\/span><span style=\"font-weight: 400; color: #993300;\">ProgrammingError<\/span><span style=\"font-weight: 400;\"> as e:<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 raise <\/span><span style=\"font-weight: 400;\">Exception<\/span><span style=\"font-weight: 400;\">(<\/span><span style=\"font-weight: 400;\">'<span style=\"color: #0000ff;\">Error<\/span><\/span><span style=\"font-weight: 400;\"> {<\/span><span style=\"font-weight: 400;\">0<\/span><span style=\"font-weight: 400;\">} ({<\/span><span style=\"font-weight: 400;\">1<\/span><span style=\"font-weight: 400;\">}): {<\/span><span style=\"font-weight: 400;\">2<\/span><span style=\"font-weight: 400;\">} ({<\/span><span style=\"font-weight: 400;\">3<\/span><span style=\"font-weight: 400;\">})'.format(e.errno, e.sqlstate, e.msg, e.sfqid))<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: center;\"><b><i>Code: to get query status(Python)<\/i><\/b><\/p>\n<h4><b><\/b><\/h4>\n<h4><b>3. Returning the response<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">Once the status is changed from <\/span><b>running<\/b><span style=\"font-weight: 400;\">, we can handle it in different ways based on the status. Here we are interested mostly in <\/span><i><span style=\"font-weight: 400;\">Succeeded<\/span><\/i><span style=\"font-weight: 400;\"> or <\/span><i><span style=\"font-weight: 400;\">Failed<\/span><\/i><span style=\"font-weight: 400;\">.<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">If <\/span><b><i>Succeeded<\/i><\/b><span style=\"font-weight: 400;\">(<\/span><i><span style=\"font-weight: 400;\">internally Snowflake returns execution status as SUCCESS<\/span><\/i><span style=\"font-weight: 400;\">), get the results from persisted cache using below query, <\/span>and format the response according to your api response needs.<\/li>\n<\/ul>\n<table style=\"background-color: #f5f5f5;\">\n<tbody>\n<tr>\n<td><span> \u00a0 \u00a0 \u00a0 \u00a0<span style=\"color: #339966;\"> &#8220;&#8221;&#8221;select * from table (result_scan(&#8216;{0}&#8217;))&#8221;&#8221;&#8221;.format(query_id)<\/span><\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: center;\"><b><i>Sql: to get result<\/i><\/b><\/p>\n<p>&nbsp;<\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">If <\/span><b><i>Failed <\/i><\/b><span style=\"font-weight: 400;\">(<\/span><i><span style=\"font-weight: 400;\">internally Snowflake returns execution status as FAILED_WITH_ERROR<\/span><\/i><span style=\"font-weight: 400;\">) , the error_message from Snowflake can be directly redirected to the api response with an error code.<\/span><\/li>\n<\/ul>\n<table style=\"background-color: #f5f5f5;\">\n<tbody>\n<tr>\n<td>\n<pre><span style=\"font-weight: 400; color: #800080;\">def<\/span> <span style=\"font-weight: 400; color: #0000ff;\">get_results<\/span><span style=\"font-weight: 400;\">(self, query_id):<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 sql = <\/span><span style=\"font-weight: 400; color: #339966;\">\"\"\"select * from table (result_scan('{0}'))\"\"\"<\/span><span style=\"font-weight: 400;\">.format(query_id)<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 print(sql)<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 items = []<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">try<\/span><span style=\"font-weight: 400;\">:<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 self.cursor.execute(sql)<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 result_set = self.cursor.fetchall()<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 # get column headers<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 columns = [col[<\/span><span style=\"font-weight: 400;\">0<\/span><span style=\"font-weight: 400;\">] <\/span><span style=\"font-weight: 400;\">for<\/span><span style=\"font-weight: 400;\"> col in self.cursor.description]<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 total_columns = len(columns)<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">for<\/span><span style=\"font-weight: 400;\"> row in result_set:<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 row_list = (list(row))<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 items.append(dict(zip(columns, row_list)))<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 results = {<\/span><span style=\"font-weight: 400;\">'<span style=\"color: #0000ff;\">column<\/span><\/span><span style=\"font-weight: 400;\"><span style=\"color: #0000ff;\">s<\/span>': {<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">'<span style=\"color: #0000ff;\">tota<\/span><\/span><span style=\"font-weight: 400;\"><span style=\"color: #0000ff;\">l<\/span>': total_columns,<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">'<span style=\"color: #0000ff;\">column<\/span><\/span><span style=\"font-weight: 400;\"><span style=\"color: #0000ff;\">s<\/span>': columns<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 },<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\">\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400;\">'<span style=\"color: #0000ff;\">item<\/span><\/span><span style=\"font-weight: 400;\"><span style=\"color: #0000ff;\">s<\/span>': items}<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 <\/span><span style=\"font-weight: 400; color: #800080;\">return<\/span><span style=\"font-weight: 400;\"> results<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 except snowflake.connector.errors.<\/span><span style=\"font-weight: 400;\">ProgrammingError<\/span><span style=\"font-weight: 400;\"> as e:<\/span><span style=\"font-weight: 400;\">\n<\/span><span style=\"font-weight: 400;\"> \u00a0 \u00a0 \u00a0 raise <\/span><span style=\"font-weight: 400;\">Exception<\/span><span style=\"font-weight: 400;\">(<\/span><span style=\"font-weight: 400;\">'Error<\/span><span style=\"font-weight: 400;\"> {<\/span><span style=\"font-weight: 400;\">0<\/span><span style=\"font-weight: 400;\">} ({<\/span><span style=\"font-weight: 400;\">1<\/span><span style=\"font-weight: 400;\">}): {<\/span><span style=\"font-weight: 400;\">2<\/span><span style=\"font-weight: 400;\">} ({<\/span><span style=\"font-weight: 400;\">3<\/span><span style=\"font-weight: 400;\">})'.format(e.errno, e.sqlstate, e.msg, e.sfqid))<\/span><\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p style=\"text-align: center;\"><b><i>Code: to get formatted results<\/i><\/b><\/p>\n<p><b><\/b><\/p>\n<h4><b>4. Asynchronous Flow<\/b><\/h4>\n<p><span style=\"font-weight: 400;\">A simple flow depicting the async service built using Api-Gateway, Lambda, Snowflake<\/span><\/p>\n<p style=\"text-align: center;\"><span style=\"font-weight: 400;\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png\" width=\"602\" height=\"296\" alt=\"\" class=\"wp-image-32258 alignnone size-full\" srcset=\"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png 602w, https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow-480x236.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 602px, 100vw\" \/><\/span><\/p>\n<p style=\"text-align: center;\"><b><i>Asynchronous flow diagram\u00a0<\/i><\/b><\/p>\n<p><b><\/b><\/p>\n<p><b><\/b><\/p>\n<h4><b>5. Time to weigh our apporach<\/b><\/h4>\n<p><strong style=\"font-size: 16px;\">Pros:<\/strong><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">If your processing function is using AWS Lambda then be aware of the Lambda timeout limit which is 15 mins.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">There is no need to build a logic to know the status of the query. Snowflake has a nice and reliable history table which maintains the status of the query in real time, which can be queried as well.<\/span><\/li>\n<\/ul>\n<p><strong>Cons:<\/strong><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">There is a small warehouse cost incurred each time a poll request is sent to the history table, whilst insignificant in small volumes this cost can quickly grow.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-size: 16px;\">Hopefully you enjoyed this microblog, and it has helps you in building an asynchronous service on a modern data warehouse like Snowflake. Watch out for more of our technical blogs.<\/span><span style=\"font-weight: 400;\"><\/span><\/p>\n<p><strong><\/strong><\/p>\n<p>&nbsp;<\/p>\n<p>[\/et_pb_text][et_pb_team_member name=&#8221;Sakthi Murugan&#8221; position=&#8221;Senior Data Engineer&#8221; image_url=&#8221;https:\/\/streamhub.co.uk\/wp-content\/uploads\/2019\/11\/sakthi-face-e1573053498270.jpg&#8221; linkedin_url=&#8221;https:\/\/www.linkedin.com\/in\/sakthi-murugan-vinayagam-05777714\/&#8221; _builder_version=&#8221;4.9.2&#8243; _module_preset=&#8221;default&#8221; width=&#8221;100%&#8221; global_colors_info=&#8221;{}&#8221;]<\/p>\n<p>Sakthi is a highly e<span>xperienced and accomplished programmer with a passion for all things Big Data, by night he is also a talented visual effects artist.\u00a0<\/span><\/p>\n<p>[\/et_pb_team_member][et_pb_blurb _builder_version=&#8221;4.9.2&#8243; _module_preset=&#8221;default&#8221; custom_margin=&#8221;|||-64px|false|false&#8221; custom_padding=&#8221;61px|||0px|false|false&#8221; global_colors_info=&#8221;{}&#8221;]<\/p>\n<p><strong>References:<\/strong><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><a href=\"https:\/\/community.snowflake.com\/s\/question\/0D50Z00007DBOk9SAH\/asynchronous-requests\"><span style=\"font-weight: 400;\">https:\/\/community.snowflake.com\/s\/question\/0D50Z00007DBOk9SAH\/asynchronous-requests<\/span><\/a><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><a href=\"https:\/\/docs.snowflake.com\/en\/user-guide\/jdbc-using.html#performing-an-asynchronous-query\"><span style=\"font-weight: 400;\">https:\/\/docs.snowflake.com\/en\/user-guide\/jdbc-using.html#performing-an-asynchronous-query<\/span><\/a><\/li>\n<\/ul>\n<p>[\/et_pb_blurb][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;4.0.6&#8243; custom_padding=&#8221;9px|||||&#8221; global_colors_info=&#8221;{}&#8221;][et_pb_column type=&#8221;4_4&#8243; _builder_version=&#8221;4.0.6&#8243; global_colors_info=&#8221;{}&#8221;][et_pb_code _builder_version=&#8221;4.9.2&#8243; _module_preset=&#8221;default&#8221; global_colors_info=&#8221;{}&#8221;][\/et_pb_code][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Reading Time: <\/span> <span class=\"rt-time\"> 5<\/span> <span class=\"rt-label rt-postfix\">minutes<\/span><\/span><\/p>\n<p>Building an asynchronous solution for your analytic use-cases can be super powerful, especially building a deep-dive on-demand reporting solution. When we started building this at Streamhub, we found very little literature around this, so I am sharing this, hoping people pondering over this, can benefit from it. Our core analytical solution for such on-demand deep-dive [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":32258,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"1080","content-type":"","_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[11,13,75],"tags":[340,342,112,121,119,341,344,343,339],"class_list":["post-32246","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blogs","category-news","category-tech","tag-async","tag-asynchronous-services","tag-data","tag-data-architecture","tag-data-pipeline","tag-data-warehousing","tag-python","tag-scala","tag-techblog"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>How to build an Asynchronous layer over Snowflake - Streamhub.co.uk<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to build an Asynchronous layer over Snowflake - Streamhub.co.uk\" \/>\n<meta property=\"og:description\" content=\"Reading Time:  5 minutesBuilding an asynchronous solution for your analytic use-cases can be super powerful, especially building a deep-dive on-demand reporting solution. When we started building this at Streamhub, we found very little literature around this, so I am sharing this, hoping people pondering over this, can benefit from it. Our core analytical solution for such on-demand deep-dive [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/\" \/>\n<meta property=\"og:site_name\" content=\"Streamhub.co.uk\" \/>\n<meta property=\"article:published_time\" content=\"2021-05-25T16:38:26+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-11-03T16:43:46+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png\" \/>\n\t<meta property=\"og:image:width\" content=\"602\" \/>\n\t<meta property=\"og:image:height\" content=\"296\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Aki\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Aki\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/\"},\"author\":{\"name\":\"Aki\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#\\\/schema\\\/person\\\/e6852db4d979f7becfd679158f7e59cd\"},\"headline\":\"How to build an Asynchronous layer over Snowflake\",\"datePublished\":\"2021-05-25T16:38:26+00:00\",\"dateModified\":\"2021-11-03T16:43:46+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/\"},\"wordCount\":1406,\"publisher\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/streamhub.co.uk\\\/wp-content\\\/uploads\\\/2021\\\/05\\\/async-flow.png\",\"keywords\":[\"async\",\"asynchronous services\",\"Data\",\"Data Architecture\",\"data pipeline\",\"data warehousing\",\"python\",\"scala\",\"techblog\"],\"articleSection\":[\"Blogs\",\"News\",\"Tech\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/\",\"url\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/\",\"name\":\"How to build an Asynchronous layer over Snowflake - Streamhub.co.uk\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/streamhub.co.uk\\\/wp-content\\\/uploads\\\/2021\\\/05\\\/async-flow.png\",\"datePublished\":\"2021-05-25T16:38:26+00:00\",\"dateModified\":\"2021-11-03T16:43:46+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/#primaryimage\",\"url\":\"https:\\\/\\\/streamhub.co.uk\\\/wp-content\\\/uploads\\\/2021\\\/05\\\/async-flow.png\",\"contentUrl\":\"https:\\\/\\\/streamhub.co.uk\\\/wp-content\\\/uploads\\\/2021\\\/05\\\/async-flow.png\",\"width\":602,\"height\":296},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/streamhub.co.uk\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to build an Asynchronous layer over Snowflake\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#website\",\"url\":\"https:\\\/\\\/streamhub.co.uk\\\/\",\"name\":\"Streamhub.co.uk\",\"description\":\"Streamhub.co.uk\",\"publisher\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/streamhub.co.uk\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#organization\",\"name\":\"Streamhub.co.uk\",\"url\":\"https:\\\/\\\/streamhub.co.uk\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/streamhub.co.uk\\\/wp-content\\\/uploads\\\/2020\\\/05\\\/SH-Logo.png\",\"contentUrl\":\"https:\\\/\\\/streamhub.co.uk\\\/wp-content\\\/uploads\\\/2020\\\/05\\\/SH-Logo.png\",\"width\":1397,\"height\":361,\"caption\":\"Streamhub.co.uk\"},\"image\":{\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/company\\\/3006156\\\/admin\\\/feed\\\/posts\\\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/streamhub.co.uk\\\/#\\\/schema\\\/person\\\/e6852db4d979f7becfd679158f7e59cd\",\"name\":\"Aki\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7396906d2a5e0d62e340832e1d78d1c4d9f69c8e097ed5851f5d07eac595f0ed?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7396906d2a5e0d62e340832e1d78d1c4d9f69c8e097ed5851f5d07eac595f0ed?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/7396906d2a5e0d62e340832e1d78d1c4d9f69c8e097ed5851f5d07eac595f0ed?s=96&d=mm&r=g\",\"caption\":\"Aki\"},\"url\":false}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to build an Asynchronous layer over Snowflake - Streamhub.co.uk","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:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/","og_locale":"en_US","og_type":"article","og_title":"How to build an Asynchronous layer over Snowflake - Streamhub.co.uk","og_description":"Reading Time:  5 minutesBuilding an asynchronous solution for your analytic use-cases can be super powerful, especially building a deep-dive on-demand reporting solution. When we started building this at Streamhub, we found very little literature around this, so I am sharing this, hoping people pondering over this, can benefit from it. Our core analytical solution for such on-demand deep-dive [&hellip;]","og_url":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/","og_site_name":"Streamhub.co.uk","article_published_time":"2021-05-25T16:38:26+00:00","article_modified_time":"2021-11-03T16:43:46+00:00","og_image":[{"width":602,"height":296,"url":"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png","type":"image\/png"}],"author":"Aki","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Aki","Est. reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/#article","isPartOf":{"@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/"},"author":{"name":"Aki","@id":"https:\/\/streamhub.co.uk\/#\/schema\/person\/e6852db4d979f7becfd679158f7e59cd"},"headline":"How to build an Asynchronous layer over Snowflake","datePublished":"2021-05-25T16:38:26+00:00","dateModified":"2021-11-03T16:43:46+00:00","mainEntityOfPage":{"@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/"},"wordCount":1406,"publisher":{"@id":"https:\/\/streamhub.co.uk\/#organization"},"image":{"@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/#primaryimage"},"thumbnailUrl":"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png","keywords":["async","asynchronous services","Data","Data Architecture","data pipeline","data warehousing","python","scala","techblog"],"articleSection":["Blogs","News","Tech"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/","url":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/","name":"How to build an Asynchronous layer over Snowflake - Streamhub.co.uk","isPartOf":{"@id":"https:\/\/streamhub.co.uk\/#website"},"primaryImageOfPage":{"@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/#primaryimage"},"image":{"@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/#primaryimage"},"thumbnailUrl":"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png","datePublished":"2021-05-25T16:38:26+00:00","dateModified":"2021-11-03T16:43:46+00:00","breadcrumb":{"@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/#primaryimage","url":"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png","contentUrl":"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png","width":602,"height":296},{"@type":"BreadcrumbList","@id":"https:\/\/streamhub.co.uk\/an-approach-to-building-asynchronous-services-async-in-next-generation-cloud-data-warehouses\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/streamhub.co.uk\/"},{"@type":"ListItem","position":2,"name":"How to build an Asynchronous layer over Snowflake"}]},{"@type":"WebSite","@id":"https:\/\/streamhub.co.uk\/#website","url":"https:\/\/streamhub.co.uk\/","name":"Streamhub.co.uk","description":"Streamhub.co.uk","publisher":{"@id":"https:\/\/streamhub.co.uk\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/streamhub.co.uk\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/streamhub.co.uk\/#organization","name":"Streamhub.co.uk","url":"https:\/\/streamhub.co.uk\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/streamhub.co.uk\/#\/schema\/logo\/image\/","url":"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2020\/05\/SH-Logo.png","contentUrl":"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2020\/05\/SH-Logo.png","width":1397,"height":361,"caption":"Streamhub.co.uk"},"image":{"@id":"https:\/\/streamhub.co.uk\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/company\/3006156\/admin\/feed\/posts\/"]},{"@type":"Person","@id":"https:\/\/streamhub.co.uk\/#\/schema\/person\/e6852db4d979f7becfd679158f7e59cd","name":"Aki","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/7396906d2a5e0d62e340832e1d78d1c4d9f69c8e097ed5851f5d07eac595f0ed?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/7396906d2a5e0d62e340832e1d78d1c4d9f69c8e097ed5851f5d07eac595f0ed?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/7396906d2a5e0d62e340832e1d78d1c4d9f69c8e097ed5851f5d07eac595f0ed?s=96&d=mm&r=g","caption":"Aki"},"url":false}]}},"views":253,"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/streamhub.co.uk\/wp-content\/uploads\/2021\/05\/async-flow.png","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/posts\/32246","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/comments?post=32246"}],"version-history":[{"count":23,"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/posts\/32246\/revisions"}],"predecessor-version":[{"id":33141,"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/posts\/32246\/revisions\/33141"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/media\/32258"}],"wp:attachment":[{"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/media?parent=32246"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/categories?post=32246"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/streamhub.co.uk\/wp-json\/wp\/v2\/tags?post=32246"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}