<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: necologicLabs</title>
    <description>The latest articles on DEV Community by necologicLabs (@necologiclabs).</description>
    <link>https://dev.to/necologiclabs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2621609%2F0f6182a0-5719-4f7d-8ce6-770b794bd8eb.png</url>
      <title>DEV Community: necologicLabs</title>
      <link>https://dev.to/necologiclabs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/necologiclabs"/>
    <language>en</language>
    <item>
      <title>Real-Time Data Integration Techniques Using PostgreSQL Foreign Data Wrapper (FDW)</title>
      <dc:creator>necologicLabs</dc:creator>
      <pubDate>Sun, 05 Jan 2025 09:12:00 +0000</pubDate>
      <link>https://dev.to/necologiclabs/real-time-data-integration-techniques-using-postgresql-foreign-data-wrapper-fdw-45bh</link>
      <guid>https://dev.to/necologiclabs/real-time-data-integration-techniques-using-postgresql-foreign-data-wrapper-fdw-45bh</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;When operating relational databases on AWS, there may be situations where you need to exchange data between multiple databases. For example, you might have &lt;strong&gt;Aurora PostgreSQL&lt;/strong&gt; as your source database containing a &lt;code&gt;Products&lt;/code&gt; table, and you want to reference it in real time from a &lt;strong&gt;PostgreSQL&lt;/strong&gt; database (the target) located in a different VPC. You then wish to perform a JOIN with the &lt;code&gt;Transactions&lt;/code&gt; table on the target side.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need for data duplication or ETL
&lt;/li&gt;
&lt;li&gt;Real-time access to the latest source data
&lt;/li&gt;
&lt;li&gt;Flexible use for historical aggregation and reporting
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These requirements can be met using &lt;strong&gt;Foreign Data Wrapper (FDW)&lt;/strong&gt;. In this article, we’ll start by explaining &lt;strong&gt;what FDW is&lt;/strong&gt;, then discuss its &lt;strong&gt;advantages and disadvantages&lt;/strong&gt;, &lt;strong&gt;network configurations&lt;/strong&gt;, and finally walk through the &lt;strong&gt;setup steps&lt;/strong&gt; in order.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Is Foreign Data Wrapper (FDW)?
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Foreign Data Wrapper (FDW)&lt;/strong&gt; is an extension feature of PostgreSQL that provides a mechanism allowing you to treat external data sources (e.g., tables from other databases) &lt;strong&gt;as if they were local tables&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
In practice, you install an FDW extension (such as &lt;code&gt;postgres_fdw&lt;/code&gt;), then configure &lt;strong&gt;“servers,” “user mappings,” and “foreign tables”&lt;/strong&gt; to reference the tables located on a remote database.&lt;/p&gt;


&lt;h1&gt;
  
  
  Advantages and Disadvantages of Using FDW
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Advantages
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Real-Time Access&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
You can always retrieve the latest data from the source database. There’s no need for ETL batch processing, making it simple to leverage the most up-to-date information.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved Development Efficiency&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
By simply writing SQL JOIN statements, you can seamlessly integrate local and remote tables, simplifying application and data analysis implementations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Data Duplication&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Compared to a batch approach that duplicates data, FDW can help minimize storage costs and prevent unnecessary data redundancy.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Disadvantages
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Performance Risks&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Because access is remote, query response times can vary depending on network latency and the load on the source database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;High Dependency on the Source DB&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If the source database experiences failures or heavy load, any queries passing through FDW will be directly affected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Limited Functionality in Some Cases&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Certain PostgreSQL features (like transaction management or triggers) may not be available on foreign tables.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h1&gt;
  
  
  Network Configuration Steps (VPC Peering or Transit Gateway)
&lt;/h1&gt;

&lt;p&gt;Even if the source (Aurora PostgreSQL) and the target (PostgreSQL) are in the &lt;strong&gt;same account&lt;/strong&gt; but reside in &lt;strong&gt;different VPCs&lt;/strong&gt;, you need to configure one of the following methods to securely enable network connectivity:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VPC Peering&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a peering connection between the source VPC and the target VPC.
&lt;/li&gt;
&lt;li&gt;Update the route tables in each VPC to include a route pointing to the peering connection for the relevant IP addresses.
&lt;/li&gt;
&lt;li&gt;Open port 5432 (PostgreSQL port) in the security groups’ inbound/outbound rules.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;AWS Transit Gateway&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you need to connect multiple VPCs or multiple Regions from a single hub, use a Transit Gateway.
&lt;/li&gt;
&lt;li&gt;Attach each VPC to the Transit Gateway and configure the necessary routes.
&lt;/li&gt;
&lt;li&gt;Similarly, make sure security groups and NACLs allow traffic on the required ports.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In either case, be sure to configure the &lt;strong&gt;correct security groups&lt;/strong&gt; to grant access to Aurora.&lt;/p&gt;


&lt;h1&gt;
  
  
  Step-by-Step Guide to Setting Up FDW
&lt;/h1&gt;

&lt;p&gt;Below is a set of concrete steps assuming the following configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: Aurora PostgreSQL (in a separate VPC)  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Endpoint&lt;/code&gt;: &lt;code&gt;maindb-instance-1.ctqegcgyi6u1.us-east-1.rds.amazonaws.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Contains a &lt;code&gt;Products&lt;/code&gt; table&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Target&lt;/strong&gt;: PostgreSQL (in a separate VPC)  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Endpoint&lt;/code&gt;: &lt;code&gt;subdb-instance-1.ctqegcgyi6u1.us-east-1.rds.amazonaws.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Contains a &lt;code&gt;Transactions&lt;/code&gt; table and needs to JOIN with &lt;code&gt;Products&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  1. Preparation on the Aurora PostgreSQL (Source) Side
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;VPC Peering or Transit Gateway Configuration&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure that the Aurora VPC and the target PostgreSQL VPC can communicate over the network.
&lt;/li&gt;
&lt;li&gt;In the Aurora instance’s security group, &lt;strong&gt;allow inbound traffic on port 5432&lt;/strong&gt; from the target side.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Table Definition in the Source Database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;product_name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;blockquote&gt;
&lt;p&gt;Assumes data is already populated.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Preparation on the PostgreSQL (Target) Side
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Launch the Target PostgreSQL Instance&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This could be RDS for PostgreSQL, PostgreSQL on EC2, a container-based setup, etc.
&lt;/li&gt;
&lt;li&gt;Make sure &lt;strong&gt;port 5432&lt;/strong&gt; is also open to accept connections.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Table Definition in the Target Database&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;Transactions&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;transaction_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;quantity&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
  &lt;span class="n"&gt;total_price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;transaction_date&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="k"&gt;CURRENT_TIMESTAMP&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;blockquote&gt;
&lt;p&gt;This will be used in the future together with the &lt;code&gt;foreign_products&lt;/code&gt; table (FDW) for JOIN operations.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Installing and Enabling FDW&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On the target database (PostgreSQL), make &lt;code&gt;postgres_fdw&lt;/code&gt; available for use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Execute on the target database 
CREATE EXTENSION IF NOT EXISTS postgres_fdw;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Depending on your managed service or PostgreSQL version, this extension may be disabled by default. You may need to enable it via the management console or similar interface.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a Server Connection (CREATE SERVER)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Register the connection information for the source database (Aurora PostgreSQL) in the target database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="n"&gt;SERVER&lt;/span&gt; &lt;span class="n"&gt;source_aurora&lt;/span&gt; &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;DATA&lt;/span&gt; &lt;span class="n"&gt;WRAPPER&lt;/span&gt; &lt;span class="n"&gt;postgres_fdw&lt;/span&gt; 
&lt;span class="k"&gt;OPTIONS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;   
    &lt;span class="k"&gt;host&lt;/span&gt; &lt;span class="s1"&gt;'maindb-instance-1.ctqegcgyi6u1.us-east-1.rds.amazonaws.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="s1"&gt;'5432'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;dbname&lt;/span&gt; &lt;span class="s1"&gt;'postgres'&lt;/span&gt;  &lt;span class="c1"&gt;-- Name of the source database&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, “source_aurora” is simply an identifier.&lt;br&gt;&lt;br&gt;
The “host” and “port” specify the Aurora connection details.&lt;br&gt;&lt;br&gt;
“dbname” is the source database name.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a User Mapping (CREATE USER MAPPING)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Set up the authentication details needed to access the source via FDW:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;MAPPING&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;target_user&lt;/span&gt; &lt;span class="n"&gt;SERVER&lt;/span&gt; &lt;span class="n"&gt;source_aurora&lt;/span&gt;  
&lt;span class="k"&gt;OPTIONS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="s1"&gt;'aurora_user'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="s1"&gt;'aurora_password'&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;USER&lt;/span&gt; &lt;span class="n"&gt;MAPPING&lt;/span&gt; &lt;span class="k"&gt;FOR&lt;/span&gt; &lt;span class="n"&gt;postgres&lt;/span&gt; &lt;span class="n"&gt;SERVER&lt;/span&gt; &lt;span class="n"&gt;source_aurora&lt;/span&gt;  
&lt;span class="k"&gt;OPTIONS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;  
    &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="s1"&gt;'postgres'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   
    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="s1"&gt;'xxx'&lt;/span&gt; 
 &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;“FOR target_user” refers to a user present on the target PostgreSQL side.&lt;br&gt;&lt;br&gt;
“user” and “password” are valid credentials for Aurora PostgreSQL.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Creating a Foreign Table (CREATE FOREIGN TABLE)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Define the &lt;code&gt;Products&lt;/code&gt; table from the Aurora source as a “foreign table” on the target:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;foreign_products&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;product_name&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;price&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; 
    &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="nb"&gt;INTEGER&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SERVER&lt;/span&gt; &lt;span class="n"&gt;source_aurora&lt;/span&gt; 
&lt;span class="k"&gt;OPTIONS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;   
    &lt;span class="k"&gt;schema_name&lt;/span&gt; &lt;span class="s1"&gt;'public'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;-- Schema in the source DB&lt;/span&gt;
    &lt;span class="k"&gt;table_name&lt;/span&gt; &lt;span class="s1"&gt;'products'&lt;/span&gt;  &lt;span class="c1"&gt;-- Table name in the source DB&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows you to run a simple query, such as &lt;code&gt;SELECT * FROM foreign_products;&lt;/code&gt; on the target database, which in turn retrieves data from the &lt;code&gt;Products&lt;/code&gt; table in the remote Aurora database.&lt;/p&gt;

&lt;p&gt;Tip: For PostgreSQL 9.5 and later, you can use the &lt;code&gt;IMPORT FOREIGN SCHEMA&lt;/code&gt; feature to import multiple tables from the source schema at once, which is convenient when you need to work with numerous tables.&lt;/p&gt;

&lt;p&gt;Confirming the Configuration&lt;br&gt;&lt;br&gt;
You can verify foreign table information using the following query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvname&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;server_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvoptions&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;server_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;um&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;umuser&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;um&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;umoptions&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;user_options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    
    &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foreign_table_name&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="k"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foreign_table_schema&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;table_schema&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt;    
    &lt;span class="n"&gt;pg_foreign_server&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt; 
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt;    
    &lt;span class="n"&gt;pg_user_mappings&lt;/span&gt; &lt;span class="n"&gt;um&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt; 
    &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;um&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvid&lt;/span&gt;  &lt;span class="c1"&gt;-- changed from umserver to srvid &lt;/span&gt;
&lt;span class="k"&gt;LEFT&lt;/span&gt; &lt;span class="k"&gt;JOIN&lt;/span&gt;     
    &lt;span class="n"&gt;information_schema&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foreign_tables&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt; 
&lt;span class="k"&gt;ON&lt;/span&gt; 
    &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;srvname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foreign_server_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Sample Results&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;server_name&lt;/td&gt;
&lt;td&gt;source_aurora&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;server_options&lt;/td&gt;
&lt;td&gt;{host=maindb-instance-1.ctqegcgyi6u1.us-east-1.rds.amazonaws.com, port=5432, dbname=postgres}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;user_id&lt;/td&gt;
&lt;td&gt;16400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;user_options&lt;/td&gt;
&lt;td&gt;{user=postgres, password=xxx}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table_name&lt;/td&gt;
&lt;td&gt;foreign_products&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;table_schema&lt;/td&gt;
&lt;td&gt;public&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Example of a JOIN Query
&lt;/h2&gt;

&lt;p&gt;Once the configuration is set up correctly, you can easily join the target’s &lt;code&gt;Transactions&lt;/code&gt; table with the remote &lt;code&gt;foreign_products&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;   
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;total_price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_date&lt;/span&gt;  
&lt;span class="k"&gt;FROM&lt;/span&gt;      
    &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; 
&lt;span class="k"&gt;JOIN&lt;/span&gt;   
    &lt;span class="n"&gt;foreign_products&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt;    
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;    
    &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Electronics'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Fields such as &lt;code&gt;f.product_name&lt;/code&gt; and &lt;code&gt;f.category&lt;/code&gt; come from the Aurora table in real time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t.transaction_date&lt;/code&gt; is a local column in the target (&lt;code&gt;Transactions&lt;/code&gt;) table.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it straightforward to &lt;strong&gt;leverage the latest source database information on the target&lt;/strong&gt; side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sample Results (Excerpt)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;            transaction_id            | product_name |  category   | quantity | total_price |  transaction_date   
--------------------------------------+--------------+-------------+----------+-------------+---------------------
 f8b8b097-75ce-47e6-8fb8-42adbf3456fc | Growth       | Electronics |        4 |      421.16 | 2025-01-02 21:57:27
 8b8a1390-6f24-4d07-9239-adc5df9ab92e | Lose         | Electronics |        6 |      448.08 | 2025-01-03 03:29:54
 86386a4b-4eda-4ff4-9854-87b65d58e3aa | Without      | Electronics |        7 |     2537.57 | 2025-01-01 20:44:28
 203291b1-24af-443e-ad34-092151a99c61 | Wonder       | Electronics |        8 |     2098.00 | 2025-01-02 14:48:15
 fd75b3fa-f564-4599-9faf-c29dd42f82e3 | How          | Electronics |        3 |     1176.63 | 2025-01-02 15:22:55
 42a281a5-de30-4bf2-b528-bd3b942e35b6 | Pattern      | Electronics |        2 |      186.56 | 2025-01-01 06:54:58
 03a7c005-9f1c-46ca-b102-352dd0ed32ae | Win          | Electronics |        6 |     2955.60 | 2025-01-01 13:39:38
 6bc0bdd8-0d9e-47a8-853a-69ac235ca983 | Successful   | Electronics |        2 |      986.18 | 2025-01-02 23:59:29
 aaffdb6e-dbd1-4f33-a788-d62bdbf012bd | Every        | Electronics |        1 |      184.57 | 2025-01-02 07:48:06
 76f0a5db-297a-42fc-b8e6-d0e874031471 | Sing         | Electronics |        3 |     1426.11 | 2025-01-03 02:17:25
 b1dd0e57-4b49-413c-9514-aeb879200138 | Paper        | Electronics |        5 |      481.60 | 2025-01-01 04:53:51
 23f60790-6cb8-4c67-8c2c-60afe30289fb | Teacher      | Electronics |        6 |      429.30 | 2025-01-02 21:37:51
 638f7951-7a70-4da5-b87d-41e681143811 | Society      | Electronics |        3 |      302.22 | 2025-01-04 04:47:11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;In PostgreSQL’s &lt;strong&gt;Foreign Data Wrapper (FDW)&lt;/strong&gt;, there is &lt;strong&gt;no built-in caching mechanism&lt;/strong&gt;. Each time you access a foreign table, a query is sent to the remote database (the server configured for FDW) to retrieve the latest data.&lt;/p&gt;

&lt;p&gt;Below are some performance measurements taken when retrieving data within the same AWS Region. The following query yielded these results:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;(5987 rows)  Time: 1094.468 ms (00:01.094)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Overall, this performance is quite good and can be considered practical for real-world use.&lt;/p&gt;




&lt;h3&gt;
  
  
  Tuning 1
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PostgreSQL Foreign Data Wrapper (FDW)&lt;/strong&gt; can push parts of query planning to the remote database to streamline communication. This is often referred to as &lt;strong&gt;query pushdown&lt;/strong&gt;. Thanks to pushdown, &lt;strong&gt;not all data must be retrieved every time&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pushdown Explained
&lt;/h4&gt;

&lt;p&gt;FDW minimizes unnecessary data transfer by sending parts of the query to the remote database. For instance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;WHERE clauses&lt;/li&gt;
&lt;li&gt;LIMIT&lt;/li&gt;
&lt;li&gt;Some JOIN conditions&lt;/li&gt;
&lt;li&gt;Queries that select only specific columns (SELECT column_name)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Query Optimization Tuning
&lt;/h4&gt;

&lt;h6&gt;
  
  
  Sample Query
&lt;/h6&gt;

&lt;p&gt;To illustrate room for improvement, let’s consider a less optimal SQL query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_sold&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;   
    &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; 
&lt;span class="k"&gt;JOIN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;    
    &lt;span class="k"&gt;SELECT&lt;/span&gt; 
        &lt;span class="o"&gt;*&lt;/span&gt; 
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;foreign_products&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt;
&lt;span class="k"&gt;ON&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt; 
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2022-01-01'&lt;/span&gt; 
&lt;span class="k"&gt;AND&lt;/span&gt;  
    &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Electronics'&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt;  
    &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt; 
&lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
        &lt;span class="n"&gt;product_id&lt;/span&gt;
    &lt;span class="k"&gt;FROM&lt;/span&gt;
        &lt;span class="n"&gt;foreign_products&lt;/span&gt;   
    &lt;span class="k"&gt;WHERE&lt;/span&gt; 
        &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
    &lt;span class="n"&gt;p1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;(830 rows) Time: 531.426 ms&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Although not terrible, it can be improved. Let’s analyze the query plan via &lt;code&gt;EXPLAIN VERBOSE (sql)&lt;/code&gt; &lt;/p&gt;

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

&lt;h5&gt;
  
  
  Problem Analysis
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Double Scanning of the Remote Table&lt;/p&gt;

&lt;p&gt;The remote table &lt;code&gt;foreign_products&lt;/code&gt; is being scanned twice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First scan:
&lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; 
    &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;product_name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt;
    &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Electronics'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Retrieves 6 rows for `category = 'Electronics'`.
&lt;/code&gt;&lt;/pre&gt;

&lt;ol&gt;
&lt;li&gt;Second scan:
&lt;/li&gt;
&lt;/ol&gt;

&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;product_id&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt; 
    &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt; 
&lt;span class="k"&gt;WHERE&lt;/span&gt;
     &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Retrieves 683 rows for `stock &amp;gt; 10`.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Problem:&lt;/p&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- The remote SQL is executed twice, increasing the communication cost with the remote database.
- Data is unnecessarily processed by a local Hash Join.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Unnecessary Local Processing&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- There is a local Hash Join happening.
- Conditions like `category` and `stock` that could be handled remotely are instead processed locally, reducing efficiency.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Full Table Scan on the Local &lt;code&gt;transactions&lt;/code&gt; Table&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- The local `transactions` table is undergoing a Seq Scan:

    `Seq Scan on public.transactions t (cost=0.00..685.00 rows=29997 width=20)    Filter: (t.transaction_date &amp;gt;= '2022-01-01')`

- Impact:
    - Because there is no index on `transaction_date`, all 29,997 rows are being scanned.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h5&gt;
  
  
  Points for Improvement
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Perform JOIN and condition filtering remotely&lt;/p&gt;

&lt;p&gt;Apply conditions (&lt;code&gt;category = 'Electronics'&lt;/code&gt; and &lt;code&gt;stock &amp;gt; 10&lt;/code&gt;) on the remote database to reduce unnecessary local joins. For instance:&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;filtered_products&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;product_name&lt;/span&gt;   
    &lt;span class="k"&gt;FROM&lt;/span&gt;       
    &lt;span class="n"&gt;foreign_products&lt;/span&gt;    
    &lt;span class="k"&gt;WHERE&lt;/span&gt;        
    &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Electronics'&lt;/span&gt;   
    &lt;span class="k"&gt;AND&lt;/span&gt;         
    &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; 
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;     
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_sold&lt;/span&gt; 
&lt;span class="k"&gt;FROM&lt;/span&gt;   
    &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; 
&lt;span class="k"&gt;JOIN&lt;/span&gt;      
    &lt;span class="n"&gt;filtered_products&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;      
&lt;span class="k"&gt;ON&lt;/span&gt; 
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt;    
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2022-01-01'&lt;/span&gt; 
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add an Index to the Local Table&lt;/p&gt;

&lt;p&gt;Create an index on &lt;code&gt;transaction_date&lt;/code&gt; in the &lt;code&gt;transactions&lt;/code&gt; table to avoid a full table scan.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  Results
&lt;/h5&gt;

&lt;p&gt;&lt;code&gt;(830 rows) Time: 387.544 ms&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is roughly a 30% reduction in execution time.&lt;/p&gt;

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

&lt;p&gt;From the query plan, you can see that remote access has been consolidated into a single call. While this example is not unique to foreign tables, inefficiencies in the query become more evident when using FDW. Hence, analyzing queries with &lt;code&gt;EXPLAIN&lt;/code&gt; is crucial for avoiding performance issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tuning 2 – Using Materialized Views for Caching
&lt;/h3&gt;

&lt;p&gt;As another method of performance tuning, consider using caching. Since FDW does not provide built-in caching by default, you can use a &lt;strong&gt;Materialized View&lt;/strong&gt; to cache data locally. This approach offloads frequent remote queries and complex processes from the remote database to the local environment, reducing load on the remote data source and further shortening query execution times.&lt;/p&gt;

&lt;h5&gt;
  
  
  Materialized View
&lt;/h5&gt;

&lt;p&gt;Below is an example of caching the entire &lt;code&gt;foreign_products&lt;/code&gt; table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE MATERIALIZED VIEW products AS SELECT * FROM foreign_products;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  SQL
&lt;/h5&gt;

&lt;p&gt;Next, use the materialized view to filter data. In the following query, only the reference to the table has been changed from &lt;code&gt;foreign_products&lt;/code&gt; to the materialized view named &lt;code&gt;products&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;WITH&lt;/span&gt; &lt;span class="n"&gt;filtered_products&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt;    
        &lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;product_name&lt;/span&gt;   
    &lt;span class="k"&gt;FROM&lt;/span&gt;       
        &lt;span class="n"&gt;products&lt;/span&gt;    
    &lt;span class="k"&gt;WHERE&lt;/span&gt;         
        &lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Electronics'&lt;/span&gt; 
    &lt;span class="k"&gt;AND&lt;/span&gt;          
        &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; 
&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="k"&gt;SELECT&lt;/span&gt;    
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="k"&gt;SUM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;quantity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;total_sold&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;     
    &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; 
&lt;span class="k"&gt;JOIN&lt;/span&gt;     
    &lt;span class="n"&gt;filtered_products&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; 
&lt;span class="k"&gt;ON&lt;/span&gt; 
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;
 &lt;span class="k"&gt;WHERE&lt;/span&gt; 
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transaction_date&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="s1"&gt;'2022-01-01'&lt;/span&gt; 
&lt;span class="k"&gt;GROUP&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; 
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;product_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;(830 rows) Time: 353.511 ms&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This yields roughly a 10% reduction in execution time. The exact effect will vary depending on data volume, query complexity, master database location, and how often the view is accessed. In this example, the entire table was cached, but caching just the subset of data you need may improve performance even more.&lt;/p&gt;

&lt;p&gt;Because a materialized view will not reflect real-time data updates, its use depends on your requirements. For instance, in a batch workflow, you could &lt;strong&gt;refresh&lt;/strong&gt; the materialized view (to get the latest data) before running the main process, then use the view locally for faster batch processing. This can be very effective.&lt;/p&gt;




&lt;p&gt;Operational Points and Considerations&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Performance Monitoring&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Since FDW is a remote connection, network latency may significantly impact queries.
- If you perform frequent JOIN operations, consider indexing and caching strategies on the source side as needed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Load on the Source Database&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- FDW directly references the latest data on the source. Repeatedly issuing heavy queries can affect the source’s performance.
- Monitor query frequency and complexity, and consider using materialized views if appropriate.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Permissions and Security&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- In addition to VPC peering and security group settings, ensure proper roles and privileges are set at the database level to restrict unwanted access.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Combining Partial Data Migration&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- If certain data does not need to be accessed in real time, using ETL or snapshots to bring it into the target might be faster.
- FDW is not a one-size-fits-all solution; combine various approaches based on the specific use case.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Dependency on PostgreSQL&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Because this approach depends on PostgreSQL features, it may constrain future system architecture decisions. Conduct sufficient reviews before committing to this design.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;p&gt;Summary&lt;/p&gt;

&lt;p&gt;By using &lt;strong&gt;Foreign Data Wrapper (FDW)&lt;/strong&gt;, you can JOIN tables across &lt;strong&gt;Aurora PostgreSQL (source)&lt;/strong&gt; and &lt;strong&gt;Aurora PostgreSQL (target)&lt;/strong&gt; even if they reside in &lt;strong&gt;separate VPCs&lt;/strong&gt;, making them appear as if they were part of the same database. Proper &lt;strong&gt;network configuration (VPC Peering or Transit Gateway)&lt;/strong&gt; and basic &lt;strong&gt;FDW setup (server, user mapping, and foreign tables)&lt;/strong&gt; enable &lt;strong&gt;real-time data access&lt;/strong&gt; with minimal effort.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Advantages&lt;/strong&gt;: Real-time access, enhanced development efficiency, reduced data duplication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disadvantages&lt;/strong&gt;: Potential performance risks, dependency on the source DB, limited functionality in certain scenarios&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The key is to set up your network, security, and source-side optimizations with care.&lt;/strong&gt; This approach is especially effective for scenarios where on-demand access to the latest data is required alongside seamless local table integration on the target side. Consider introducing it in your next project if it meets your requirements.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>aurora</category>
      <category>postgres</category>
      <category>database</category>
    </item>
    <item>
      <title>Mastering AWS Incident Management: Automating Responses with Systems Manager Incident Manager</title>
      <dc:creator>necologicLabs</dc:creator>
      <pubDate>Fri, 03 Jan 2025 07:06:36 +0000</pubDate>
      <link>https://dev.to/necologiclabs/mastering-aws-incident-management-automating-responses-with-systems-manager-incident-manager-3m8j</link>
      <guid>https://dev.to/necologiclabs/mastering-aws-incident-management-automating-responses-with-systems-manager-incident-manager-3m8j</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;When handling increased error rates in AWS Lambda, categorizing errors and defining escalation paths is crucial. This guide demonstrates how to use AWS Systems Manager Incident Manager to automatically handle and escalate incidents effectively. The workflow involves collecting error details using Runbooks and notifying stakeholders through Amazon SNS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use AWS Systems Manager Incident Manager?
&lt;/h2&gt;

&lt;p&gt;AWS Systems Manager Incident Manager provides centralized management for incident response within AWS environments. Key benefits include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Native AWS Integration&lt;/strong&gt;: Seamlessly integrates with services like Amazon CloudWatch, AWS Lambda, and Amazon EventBridge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Runbook Automation&lt;/strong&gt;: Facilitates automated or semi-automated workflows to troubleshoot and address incidents.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multi-Channel Notifications&lt;/strong&gt;: Supports notifications via Amazon SNS, Slack, and Amazon Chime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cost Efficiency&lt;/strong&gt;: A viable alternative to commercial solutions for small-to-medium environments.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;p&gt;For large-scale organizations requiring detailed reporting, complex team hierarchies, and multi-layer escalation flows, specialized tools like PagerDuty or ServiceNow may be more appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;The architecture monitors AWS Lambda functions for errors using CloudWatch Alarms. Incident Manager automatically creates incidents and executes Runbooks for error handling and notifications.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Error Scenarios
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error A&lt;/strong&gt;: Standard incident with email notifications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error B&lt;/strong&gt;: Critical incident requiring SMS notifications and escalations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CloudWatch Alarms are configured to distinguish between these error types, triggering specific incident responses accordingly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Create CloudWatch Alarms for Lambda Errors
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Example Lambda Function:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setLevel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;error_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;errorType&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;error_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error A: A standard exception occurred.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error A occurred&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;error_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;B&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error B: A critical runtime error occurred.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Critical Error B occurred&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No error triggered.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;An error occurred: %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configure CloudWatch Metrics and Alarms:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Metrics Filters&lt;/strong&gt;: Create filters for &lt;code&gt;Error A&lt;/code&gt; and &lt;code&gt;Error B&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

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

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Alarms&lt;/strong&gt;: Link these filters to alarms with appropriate thresholds and periods.&lt;/li&gt;
&lt;/ol&gt;

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

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Alarm Actions&lt;/strong&gt;: Set up triggers to initiate Incident Manager workflows.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;h3&gt;
  
  
  Step 2: Set Up Incident Manager
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Enable Incident Manager&lt;/strong&gt;:&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Navigate to the Incident Manager settings in the AWS Management Console and onboard your account.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Step 3: Configure Notification Contacts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Email&lt;/strong&gt;: Notify administrators for &lt;code&gt;Error A&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SMS&lt;/strong&gt;: Notify stakeholders for &lt;code&gt;Error B&lt;/code&gt; escalation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxiniapcpa12cnzyc40ab.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxiniapcpa12cnzyc40ab.png" alt="Image description" width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: Define Escalation Plans
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error A&lt;/strong&gt;: Email notification followed by SMS if unresolved.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error B&lt;/strong&gt;: Immediate SMS notification.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tp2ln0q3ohq2sd9tyh4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3tp2ln0q3ohq2sd9tyh4.png" alt="Image description" width="800" height="372"&gt;&lt;/a&gt;    &lt;/p&gt;
&lt;h3&gt;
  
  
  Step 5: Create a Runbook
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Runbook Template:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;schemaVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0.3'&lt;/span&gt;
&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Runbook&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Lambda&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;handling."&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;AlarmName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Name&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CloudWatch&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Alarm"&lt;/span&gt;
  &lt;span class="na"&gt;snsTopicArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;String&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SNS&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Topic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ARN&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;notifications"&lt;/span&gt;
&lt;span class="na"&gt;mainSteps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GatherErrorLogs&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws:executeScript&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;python3.8&lt;/span&gt;
      &lt;span class="na"&gt;Script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;def script_handler(events, context):&lt;/span&gt;
            &lt;span class="s"&gt;return {"status": "Logs gathered"}&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;SendNotification&lt;/span&gt;
    &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws:executeAwsApi&lt;/span&gt;
    &lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sns&lt;/span&gt;
      &lt;span class="na"&gt;Api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Publish&lt;/span&gt;
      &lt;span class="na"&gt;TopicArn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;snsTopicArn&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
      &lt;span class="na"&gt;Message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Lambda&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Errors&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;detected.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AlarmName:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;AlarmName&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Create Response Plans
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Define separate response plans for &lt;code&gt;Error A&lt;/code&gt; and &lt;code&gt;Error B&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Link Runbooks and notification channels to each response plan.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 7: Link CloudWatch Alarms to Incident Manager
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Edit alarm actions to trigger the corresponding Incident Manager response plans.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyioxe1qgssijfujoih9a.png" alt="Image description" width="800" height="201"&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

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

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

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

&lt;h2&gt;
  
  
  Commercial Tools Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AWS Incident Manager&lt;/th&gt;
&lt;th&gt;PagerDuty&lt;/th&gt;
&lt;th&gt;ServiceNow&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost Efficiency&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AWS Integration&lt;/td&gt;
&lt;td&gt;Seamless&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Escalation Flexibility&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reporting and Analytics&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;Advanced&lt;/td&gt;
&lt;td&gt;Advanced&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Ideal Use Cases for AWS Incident Manager:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Small-to-medium environments with AWS-centric architectures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Simple escalation and notification needs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost-sensitive deployments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;AWS Systems Manager Incident Manager is a cost-effective tool for incident response in AWS-centric environments. While it lacks some advanced features of commercial solutions, it offers robust integration with AWS services and sufficient functionality for many use cases. Its ease of setup and low cost make it an attractive choice for small to medium-scale operations.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/incidents.html" rel="noopener noreferrer"&gt;AWS Systems Manager Incident Manager&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/monitoring-metrics.html" rel="noopener noreferrer"&gt;AWS Lambda Monitoring&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/cloudwatch/?id=docs_gateway" rel="noopener noreferrer"&gt;Amazon CloudWatch Alarms&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.pagerduty.com/" rel="noopener noreferrer"&gt;PagerDuty&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.servicenow.com/" rel="noopener noreferrer"&gt;ServiceNow&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>systemsmanager</category>
      <category>incidentmanager</category>
      <category>aws</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Distributed Tracing in Microservices: AWS X-Ray vs DataDog</title>
      <dc:creator>necologicLabs</dc:creator>
      <pubDate>Sat, 28 Dec 2024 13:18:08 +0000</pubDate>
      <link>https://dev.to/necologiclabs/distributed-tracing-in-microservices-aws-x-ray-vs-datadog-4n8n</link>
      <guid>https://dev.to/necologiclabs/distributed-tracing-in-microservices-aws-x-ray-vs-datadog-4n8n</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;Microservice architectures significantly enhance scalability and development efficiency by dividing applications into smaller, independent services. However, they also introduce challenges such as visualizing service communication, monitoring performance, and identifying root causes of failures.&lt;/p&gt;

&lt;p&gt;This article explores the importance of distributed tracing and provides a detailed comparison of two leading tools: &lt;strong&gt;AWS X-Ray&lt;/strong&gt; and &lt;strong&gt;DataDog&lt;/strong&gt;. Additionally, we demonstrate a practical example using a sample application flow: &lt;strong&gt;FunctionA → SQS → FunctionB&lt;/strong&gt;, highlighting key points for implementation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvw91hsveg7wjct8phz2k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvw91hsveg7wjct8phz2k.png" alt="MicroService Architecture" width="800" height="397"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.splunk.com/ja_jp/data-insider/what-is-distributed-tracing.html" rel="noopener noreferrer"&gt;https://www.splunk.com/ja_jp/data-insider/what-is-distributed-tracing.html&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Distributed Tracing in Microservices: AWS X-Ray vs DataDog

&lt;ul&gt;
&lt;li&gt;Overview&lt;/li&gt;
&lt;li&gt;Table of Contents&lt;/li&gt;
&lt;li&gt;Introduction: The Importance of Distributed Tracing in Microservices&lt;/li&gt;
&lt;li&gt;Challenges of Debugging and Tracing in Microservices&lt;/li&gt;
&lt;li&gt;Why AWS X-Ray and DataDog?&lt;/li&gt;
&lt;li&gt;AWS X-Ray&lt;/li&gt;
&lt;li&gt;DataDog&lt;/li&gt;
&lt;li&gt;Feature Comparison&lt;/li&gt;
&lt;li&gt;Tracing Demo with a Sample Application&lt;/li&gt;
&lt;li&gt;5.1 Architecture Overview&lt;/li&gt;
&lt;li&gt;5.2 Key Points for Tracing with AWS X-Ray&lt;/li&gt;
&lt;li&gt;5.3 Key Points for Tracing with DataDog&lt;/li&gt;
&lt;li&gt;Cost and Optimization&lt;/li&gt;
&lt;li&gt;AWS X-Ray&lt;/li&gt;
&lt;li&gt;DataDog&lt;/li&gt;
&lt;li&gt;Choosing the Right Tool&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Introduction: The Importance of Distributed Tracing in Microservices
&lt;/h2&gt;

&lt;p&gt;Microservices divide applications into smaller, manageable services to improve scalability and development efficiency. However, this architecture also presents challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Visualizing Service Communication:&lt;/strong&gt; Tracking how services interact and ensuring smooth communication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Identifying Problem Areas:&lt;/strong&gt; Quickly locating latency bottlenecks or errors between services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improving Overall Performance:&lt;/strong&gt; Understanding bottlenecks to implement optimization strategies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9vz6oknx94h3ej19z05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo9vz6oknx94h3ej19z05.png" alt="Distribute Tracing" width="800" height="330"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.jaegertracing.io/docs/1.33/architecture" rel="noopener noreferrer"&gt;https://www.jaegertracing.io/docs/1.33/architecture&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Distributed tracing addresses these issues by providing a clear view of the entire workflow across services.&lt;/p&gt;




&lt;h2&gt;
  
  
  Challenges of Debugging and Tracing in Microservices
&lt;/h2&gt;

&lt;p&gt;Distributed tracing is essential due to these specific challenges in microservices:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Distributed Logging:&lt;/strong&gt; Logs are spread across independent services, making collection and analysis complex.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complexity in Debugging:&lt;/strong&gt; Identifying failures in a system with multiple dependencies is more challenging.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability Requirements:&lt;/strong&gt; Metrics, logs, and traces are necessary to provide a comprehensive view of the system’s health and performance.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why AWS X-Ray and DataDog?
&lt;/h2&gt;

&lt;p&gt;Among the many tracing tools available, &lt;strong&gt;AWS X-Ray&lt;/strong&gt; and &lt;strong&gt;DataDog&lt;/strong&gt; stand out for their capabilities and compatibility with various use cases.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS X-Ray
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tight Integration with AWS:&lt;/strong&gt; Simplifies implementation with AWS services like Lambda, ECS, and Fargate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparent Pricing:&lt;/strong&gt; Easy to calculate costs alongside AWS resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service Map Visualization:&lt;/strong&gt; Provides a clear view of dependencies between services.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DataDog
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Cloud and Hybrid Support:&lt;/strong&gt; Works seamlessly across AWS, GCP, Azure, and on-premises environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comprehensive Observability:&lt;/strong&gt; Combines tracing, logging, and infrastructure monitoring into a single platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Highly Customizable Dashboards:&lt;/strong&gt; Offers rich visualization with tag-based filtering.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Feature Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AWS X-Ray&lt;/th&gt;
&lt;th&gt;DataDog&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Visualization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Service Map for dependency analysis&lt;/td&gt;
&lt;td&gt;Advanced dashboards with service mapping&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instrumentation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;SDK-based, manual or automatic&lt;/td&gt;
&lt;td&gt;Automatic via agent or library integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supported Platforms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AWS-centric (EC2, Lambda, etc.)&lt;/td&gt;
&lt;td&gt;Multi-cloud and on-premises&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Metrics Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Works seamlessly with CloudWatch&lt;/td&gt;
&lt;td&gt;Highly customizable external integrations&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Log Management&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CloudWatch Logs integration&lt;/td&gt;
&lt;td&gt;Built-in log management (paid)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;UI/Customization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple and functional&lt;/td&gt;
&lt;td&gt;Highly customizable, modern UI&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Tracing Demo with a Sample Application
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Architecture Overview
&lt;/h3&gt;

&lt;p&gt;We’ll use a simple serverless flow for this demonstration:&lt;/p&gt;

&lt;p&gt;[API Gateway] → (FunctionA) → [SQS] → (FunctionB)&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;FunctionA:&lt;/strong&gt; Receives requests from API Gateway and queues messages in SQS.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQS:&lt;/strong&gt; Processes messages asynchronously and triggers FunctionB.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FunctionB:&lt;/strong&gt; Processes SQS messages, writes to a database, and logs results.&lt;/li&gt;
&lt;/ol&gt;

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




&lt;h3&gt;
  
  
  5.2 Key Points for Tracing with AWS X-Ray
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Setup:&lt;/strong&gt; Enable &lt;strong&gt;Active Tracing&lt;/strong&gt; in Lambda and integrate X-Ray SDK for additional details.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualization:&lt;/strong&gt; X-Ray’s Service Map displays API Gateway, Lambda, and SQS as connected components, showing processing times and errors.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsaa9ci598klvivqixog2.png" alt="X-RAY1" width="800" height="127"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detailed Analysis:&lt;/strong&gt; Identify cold starts and bottlenecks within the service chain.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftt16i9jjeqas8wndxn7a.png" alt="X-RAY2" width="800" height="317"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Considerations:&lt;/strong&gt; While great for AWS environments, X-Ray lacks support for multi-cloud setups.&lt;/li&gt;
&lt;/ol&gt;

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

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




&lt;h3&gt;
  
  
  5.3 Key Points for Tracing with DataDog
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Setup:&lt;/strong&gt; Use &lt;strong&gt;DataDog Lambda Library&lt;/strong&gt; or agent for seamless integration.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tags and Filtering:&lt;/strong&gt; Tag services and requests with meaningful labels (e.g., environment or version).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rich Dashboards:&lt;/strong&gt; Use APM’s Service Map and built-in logs for comprehensive observability.
&lt;/li&gt;
&lt;/ol&gt;

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

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

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

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Considerations:&lt;/strong&gt; Ideal for hybrid and multi-cloud systems but may involve higher costs.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Cost and Optimization
&lt;/h2&gt;

&lt;h3&gt;
  
  
  AWS X-Ray
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pay-per-Trace:&lt;/strong&gt; Costs are proportional to the number of traces and data volume.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Unified with AWS Services:&lt;/strong&gt; Simplifies budget management for AWS-only environments.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DataDog
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Module-Based Pricing:&lt;/strong&gt; Separate charges for APM, logging, and infrastructure monitoring.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficiency Gains:&lt;/strong&gt; Reduces overhead by consolidating observability tools.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Choosing the Right Tool
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;AWS X-Ray&lt;/th&gt;
&lt;th&gt;DataDog&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS-Centric Projects&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Best for AWS-only architectures&lt;/td&gt;
&lt;td&gt;Handles multi-cloud or hybrid environments&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Serverless Workflows&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Excellent with Lambda and API Gateway&lt;/td&gt;
&lt;td&gt;Supports serverless and multi-cloud setups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Team Requirements&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Works well for small teams&lt;/td&gt;
&lt;td&gt;Suitable for DevOps/SRE teams with large setups&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Budget Constraints&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cost-effective for AWS-only use cases&lt;/td&gt;
&lt;td&gt;Flexible but potentially expensive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




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

&lt;p&gt;Distributed tracing is essential for visualizing complex workflows, identifying bottlenecks, and improving microservice performance. &lt;strong&gt;AWS X-Ray&lt;/strong&gt; is an excellent choice for AWS-centric serverless projects due to its seamless integration and cost-effectiveness. &lt;strong&gt;DataDog&lt;/strong&gt;, on the other hand, excels in hybrid or multi-cloud setups with its rich features and flexibility.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/xray/latest/devguide/" rel="noopener noreferrer"&gt;AWS X-Ray Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.datadoghq.com/" rel="noopener noreferrer"&gt;DataDog Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>aws</category>
      <category>awsxray</category>
      <category>datadog</category>
      <category>microservices</category>
    </item>
    <item>
      <title>AWS SAM vs. Serverless Framework: Choosing the Right Framework for Serverless Development</title>
      <dc:creator>necologicLabs</dc:creator>
      <pubDate>Fri, 27 Dec 2024 13:22:49 +0000</pubDate>
      <link>https://dev.to/necologiclabs/aws-sam-vs-serverless-framework-choosing-the-right-framework-for-serverless-development-45oj</link>
      <guid>https://dev.to/necologiclabs/aws-sam-vs-serverless-framework-choosing-the-right-framework-for-serverless-development-45oj</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Challenge
&lt;/h3&gt;

&lt;p&gt;As serverless development becomes more popular, many developers rely on frameworks like &lt;strong&gt;AWS SAM&lt;/strong&gt; and &lt;strong&gt;Serverless Framework&lt;/strong&gt; to build applications. However, deciding which tool to use can be challenging, especially when their functionalities overlap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Purpose of This Article
&lt;/h3&gt;

&lt;p&gt;This article compares AWS SAM and Serverless Framework, highlighting their features, use cases, and strengths. By the end, you’ll be able to choose the best tool for your project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Background: The Growth of Serverless Architecture
&lt;/h2&gt;

&lt;p&gt;Serverless architecture has become a compelling choice in recent years, offering numerous advantages.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Evolution of Cloud Technology
&lt;/h3&gt;

&lt;p&gt;Cloud technology has evolved through three significant phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Machines (VMs):&lt;/strong&gt; Easy to migrate but require infrastructure management.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Containers:&lt;/strong&gt; Lightweight virtualization enhancing portability and scalability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless:&lt;/strong&gt; Offloads all infrastructure management to cloud providers, allowing developers to focus solely on application logic.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  2. Business Drivers Behind Serverless Adoption
&lt;/h3&gt;

&lt;p&gt;Enterprises prioritize:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Development Speed:&lt;/strong&gt; Focus on building applications without managing runtime environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost Efficiency:&lt;/strong&gt; Pay-as-you-go pricing minimizes wasted resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; Built-in autoscaling adjusts automatically to traffic demands.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Technical Benefits
&lt;/h3&gt;

&lt;p&gt;Serverless architecture offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Automated Scaling:&lt;/strong&gt; Handles concurrent executions seamlessly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Productivity:&lt;/strong&gt; Developers focus on logic, not infrastructure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compatibility:&lt;/strong&gt; Works well with modern architectures like microservices and event-driven systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Cloud Ecosystems
&lt;/h3&gt;

&lt;p&gt;AWS Lambda, API Gateway, and DynamoDB exemplify how serverless ecosystems enable rapid development. Similar offerings from Google Cloud and Azure further validate serverless as a mainstream choice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why AWS SAM and Serverless Framework?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Key Reasons
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Market Presence:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS SAM:&lt;/strong&gt; AWS’s official tool for serverless applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless Framework:&lt;/strong&gt; A leading choice for multi-cloud environments.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Developer Support:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS SAM integrates deeply with AWS resources.&lt;/li&gt;
&lt;li&gt;Serverless Framework provides extensive plugins and community-driven support.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complementary Use Cases:&lt;/strong&gt; These tools cater to distinct needs, making them excellent candidates for comparison.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Points of Comparison
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Implementation and Development Efficiency:&lt;/strong&gt; How each tool structures applications and supports productivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment and Operational Flexibility:&lt;/strong&gt; Differences in deployment workflows and constraints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration with AWS Services:&lt;/strong&gt; SAM’s AWS-centric features versus Serverless Framework’s flexibility.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Sample Application: Task Management
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;This sample application demonstrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB:&lt;/strong&gt; Manages task data (e.g., &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;task&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Gateway and Lambda:&lt;/strong&gt; Provides REST endpoints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DynamoDB Streams and SNS:&lt;/strong&gt; Sends email notifications for task status updates.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  API Endpoints
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GET&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/task?id=1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Retrieves task by ID.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;POST&lt;/td&gt;
&lt;td&gt;&lt;code&gt;/task&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Updates or creates a task.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  AWS SAM: AWS-Centric Power
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Integration:&lt;/strong&gt; Seamless support for AWS services like DynamoDB and SNS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robust Local Testing:&lt;/strong&gt; High fidelity testing with &lt;code&gt;sam local&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use Case:&lt;/strong&gt; Ideal for AWS-heavy environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Limited support for non-AWS services.&lt;/li&gt;
&lt;li&gt;Complex configurations may require familiarity with CloudFormation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Template
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;AWSTemplateFormatVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2010-09-09'&lt;/span&gt;
&lt;span class="na"&gt;Transform&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless-2016-10-31&lt;/span&gt;

&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="s"&gt;sam-task-app - A simple task management application with DynamoDB, API Gateway, and SNS.&lt;/span&gt;

&lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;TaskTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::DynamoDB::Table&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TaskTable&lt;/span&gt;
      &lt;span class="na"&gt;AttributeDefinitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
          &lt;span class="na"&gt;AttributeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S&lt;/span&gt;
      &lt;span class="na"&gt;KeySchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
          &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HASH&lt;/span&gt;
      &lt;span class="na"&gt;BillingMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PAY_PER_REQUEST&lt;/span&gt;
      &lt;span class="na"&gt;StreamSpecification&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;StreamViewType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NEW_AND_OLD_IMAGES&lt;/span&gt;

  &lt;span class="na"&gt;TaskApiFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task-api/app.lambdaHandler&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs18.x&lt;/span&gt;
      &lt;span class="na"&gt;CodeUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task-api/&lt;/span&gt;
      &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;TABLE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TaskTable&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;DynamoDBCrudPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TaskTable&lt;/span&gt;
      &lt;span class="na"&gt;Events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;TaskApi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Api&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/task&lt;/span&gt;
            &lt;span class="na"&gt;Method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;any&lt;/span&gt;

  &lt;span class="na"&gt;StreamHandlerFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::Serverless::Function&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stream-handler/app.lambdaHandler&lt;/span&gt;
      &lt;span class="na"&gt;Runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs18.x&lt;/span&gt;
      &lt;span class="na"&gt;CodeUri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;stream-handler/&lt;/span&gt;
      &lt;span class="na"&gt;Environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;TOPIC_ARN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;NotificationTopic&lt;/span&gt;
      &lt;span class="na"&gt;Policies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
            &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sns:Publish&lt;/span&gt;
            &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;NotificationTopic&lt;/span&gt;
      &lt;span class="na"&gt;Events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;StreamEvent&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DynamoDB&lt;/span&gt;
          &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Stream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;TaskTable.StreamArn&lt;/span&gt;
            &lt;span class="na"&gt;StartingPosition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TRIM_HORIZON&lt;/span&gt;

  &lt;span class="na"&gt;NotificationTopic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SNS::Topic&lt;/span&gt;
    &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Subscription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
          &lt;span class="na"&gt;Endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xxx@gmail.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Serverless Framework: Flexibility First
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Strengths
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Cloud Support:&lt;/strong&gt; Works with AWS, Azure, GCP, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plugin Ecosystem:&lt;/strong&gt; Highly customizable through plugins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use Case:&lt;/strong&gt; Suitable for diverse, non-AWS-exclusive projects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Lacks built-in AWS-specific configurations like SAM’s &lt;code&gt;Policies&lt;/code&gt; shortcuts.&lt;/li&gt;
&lt;li&gt;May require extra setup for advanced AWS integrations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Template
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;org&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;neclogoiclabs&lt;/span&gt;
&lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sls-task-app&lt;/span&gt;
&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sls-test&lt;/span&gt;

&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;individually&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./**&lt;/span&gt;

&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-plugin-common-excludes&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-plugin-include-dependencies&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;serverless-iam-roles-per-function&lt;/span&gt;

&lt;span class="na"&gt;provider&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws&lt;/span&gt;
  &lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nodejs18.x&lt;/span&gt;
  &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;

&lt;span class="na"&gt;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;apiHandler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/api/index.apiHandler&lt;/span&gt;
    &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/api/**&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;task&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;any&lt;/span&gt;
    &lt;span class="na"&gt;iamRoleStatements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
        &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dynamodb:GetItem&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;dynamodb:PutItem&lt;/span&gt;
        &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
          &lt;span class="kt"&gt;!GetAtt&lt;/span&gt; &lt;span class="s"&gt;TaskTable.Arn&lt;/span&gt;

  &lt;span class="na"&gt;streamHandler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;src/stream/index.streamHandler&lt;/span&gt;
    &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src/stream/**&lt;/span&gt;    
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;TOPIC_ARN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;TaskNotificationTopic&lt;/span&gt;
    &lt;span class="na"&gt;events&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dynamodb&lt;/span&gt;
          &lt;span class="na"&gt;arn&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;Fn::GetAtt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;TaskTable&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;StreamArn&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;iamRoleStatements&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Effect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Allow&lt;/span&gt;
        &lt;span class="na"&gt;Action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sns:Publish&lt;/span&gt;
        &lt;span class="na"&gt;Resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="kt"&gt;!Ref&lt;/span&gt; &lt;span class="s"&gt;TaskNotificationTopic&lt;/span&gt;
&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Resources&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;TaskTable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::DynamoDB::Table&lt;/span&gt;
      &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TaskTable&lt;/span&gt;
        &lt;span class="na"&gt;AttributeDefinitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
            &lt;span class="na"&gt;AttributeType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S&lt;/span&gt;
        &lt;span class="na"&gt;KeySchema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;AttributeName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
            &lt;span class="na"&gt;KeyType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HASH&lt;/span&gt;
        &lt;span class="na"&gt;BillingMode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PAY_PER_REQUEST&lt;/span&gt;
        &lt;span class="na"&gt;StreamSpecification&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;StreamViewType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NEW_AND_OLD_IMAGES&lt;/span&gt;

    &lt;span class="na"&gt;TaskNotificationTopic&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;AWS::SNS::Topic&lt;/span&gt;
        &lt;span class="na"&gt;Properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;TopicName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TaskNotificationTopic&lt;/span&gt;
          &lt;span class="na"&gt;Subscription&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;Protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;email&lt;/span&gt;
              &lt;span class="na"&gt;Endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;xxx@gmail.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






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

&lt;p&gt;Both frameworks have unique strengths. Consider the following when choosing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Choose AWS SAM&lt;/strong&gt; for AWS-specific projects requiring deep service integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Choose Serverless Framework&lt;/strong&gt; for multi-cloud scenarios or projects needing high customization.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html" rel="noopener noreferrer"&gt;AWS SAM Official Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.serverless.com/framework/docs" rel="noopener noreferrer"&gt;Serverless Framework Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>awssam</category>
      <category>serverlessframewok</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Microservices Clean Architecture: Key Design Points and Migration Strategies</title>
      <dc:creator>necologicLabs</dc:creator>
      <pubDate>Fri, 27 Dec 2024 13:13:24 +0000</pubDate>
      <link>https://dev.to/necologiclabs/microservices-x-clean-architecture-key-design-points-and-migration-strategies-6i0</link>
      <guid>https://dev.to/necologiclabs/microservices-x-clean-architecture-key-design-points-and-migration-strategies-6i0</guid>
      <description>&lt;p&gt;In this article, we'll explore how to apply &lt;strong&gt;Clean Architecture&lt;/strong&gt; principles when transitioning from a monolithic system to &lt;strong&gt;microservices&lt;/strong&gt;. We'll address common challenges such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Designing adapter layers (for database access and external API calls)
&lt;/li&gt;
&lt;li&gt;Handling master data across multiple services
&lt;/li&gt;
&lt;li&gt;Dealing with code duplication
&lt;/li&gt;
&lt;li&gt;Managing performance impacts when table joins are no longer straightforward
&lt;/li&gt;
&lt;li&gt;Planning a phased approach to migrate from a monolith&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you're starting fresh with microservices or modernizing a legacy system, these insights will help you build a flexible, maintainable architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Clean Architecture × Microservices Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1 What Is Clean Architecture?
&lt;/h3&gt;

&lt;p&gt;Clean Architecture emphasizes &lt;strong&gt;separating business logic&lt;/strong&gt; (the application core) from external elements (databases, UI, external APIs). At its heart:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application Core (Use Cases, Entities):&lt;/strong&gt; Encapsulates the essential business rules.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adapters (or Interface/Infrastructure Layer):&lt;/strong&gt; Handles external operations (DB queries, API calls, I/O) while shielding the core from infrastructure details.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  1.2 What Is Microservices Architecture?
&lt;/h3&gt;

&lt;p&gt;Microservices break a system into &lt;strong&gt;independently deployable services&lt;/strong&gt;, each owning its own data store. Communication occurs via &lt;strong&gt;network calls&lt;/strong&gt; (REST, gRPC, messaging, etc.). This approach increases development agility and scalability but also introduces concerns about data consistency, service orchestration, and operational overhead.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  1.3 Why Combine the Two?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clean Architecture:&lt;/strong&gt; Strengthens each microservice internally so that core business logic remains independent of infrastructure details.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microservices:&lt;/strong&gt; Allows teams to scale and release features at the service level.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By mixing Clean Architecture with microservices, you maintain &lt;strong&gt;loose coupling&lt;/strong&gt; and &lt;strong&gt;high scalability&lt;/strong&gt;, while preserving clarity in your domain logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. The Adapter Layer — DB Access &amp;amp; External API Calls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1 Role of the Adapter Layer
&lt;/h3&gt;

&lt;p&gt;In Clean Architecture, you &lt;strong&gt;avoid pushing external dependencies&lt;/strong&gt; directly into the core. Instead, all external I/O, such as database queries or API requests, happens in an adapter layer. The core interacts only with &lt;strong&gt;abstract interfaces&lt;/strong&gt; (ports), making it easy to switch implementations.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  2.2 DB Access Adapter
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each microservice typically manages its own database.
&lt;/li&gt;
&lt;li&gt;The adapter handles all CRUD operations, encapsulating details like SQL or ORM usage.
&lt;/li&gt;
&lt;li&gt;The core (use cases) relies on an interface that the DB adapter implements.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.3 External API Integration Adapter
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For cross-service or third-party API calls, the adapter manages protocols, request/response formats, and error handling (e.g., retries, circuit breakers).
&lt;/li&gt;
&lt;li&gt;This approach keeps the core’s business logic &lt;strong&gt;independent&lt;/strong&gt; of external service details.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Master Data Handling — Turning Common Data into a Separate Service
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 What Is a Master Data Service?
&lt;/h3&gt;

&lt;p&gt;When multiple services need the same reference data (e.g., country lists, category definitions), you can &lt;strong&gt;centralize&lt;/strong&gt; it in a &lt;strong&gt;Master Data Service&lt;/strong&gt;.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensures &lt;strong&gt;consistent&lt;/strong&gt; data usage across services
&lt;/li&gt;
&lt;li&gt;Simplifies updates by localizing changes to one service&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h3&gt;
  
  
  3.2 Pros and Cons
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Strong data consistency
&lt;/li&gt;
&lt;li&gt;Single point for updates
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Cons&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Potential single point of failure if not designed with redundancy
&lt;/li&gt;
&lt;li&gt;Increased &lt;strong&gt;latency&lt;/strong&gt; from external API calls&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mitigation Tips:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use caching (e.g., Redis) to avoid excessive calls.
&lt;/li&gt;
&lt;li&gt;Implement circuit breakers and retries for resilience.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  4. Code Duplication — Balancing DRY and Service Independence
&lt;/h2&gt;

&lt;h3&gt;
  
  
  4.1 The DRY Principle vs. Microservice Independence
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Ideally, you reduce duplication by placing &lt;strong&gt;common logic&lt;/strong&gt; into libraries or SDKs.
&lt;/li&gt;
&lt;li&gt;However, microservices often &lt;strong&gt;deliberately&lt;/strong&gt; allow some duplication to keep services truly decoupled, each evolving at its own pace.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4.2 Minimizing Duplication
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Create a Common Library&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Distribute shared API client code, data transformation logic, or utility functions.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use an API Gateway or Service Mesh&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Centralize cross-cutting concerns like authentication, routing, or retries.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage Shared Caching Strategies&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Provide a standardized approach so each service doesn’t reimplement the same patterns.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Table Example:&lt;/strong&gt;  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Common Library (SDK)&lt;/td&gt;
&lt;td&gt;Easy to apply DRY; single source of truth&lt;/td&gt;
&lt;td&gt;Version conflicts across services&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Gateway&lt;/td&gt;
&lt;td&gt;Simplifies client requests; reduces overhead&lt;/td&gt;
&lt;td&gt;Gateway can become a single point of failure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intentional Duplication&lt;/td&gt;
&lt;td&gt;Each service can evolve independently&lt;/td&gt;
&lt;td&gt;Fixes/updates must be applied in multiple places&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  5. Dealing with the Loss of Table Joins &amp;amp; Performance Impacts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 From Monolith to Distributed Data
&lt;/h3&gt;

&lt;p&gt;In a monolith, you can easily use &lt;strong&gt;JOIN&lt;/strong&gt; queries. In microservices, each service owns its own data, making direct joins &lt;strong&gt;impossible&lt;/strong&gt;. This demands alternative solutions for queries spanning multiple services.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Data Integration Patterns
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CQRS (Command Query Responsibility Segregation)&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separate &lt;strong&gt;read&lt;/strong&gt; models from &lt;strong&gt;write&lt;/strong&gt; models.
&lt;/li&gt;
&lt;li&gt;Maintain a &lt;strong&gt;read-optimized&lt;/strong&gt; view (materialized view or “query side”) using events or batch updates.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data Aggregation Service&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A specialized service that fetches data from multiple services, combines it, and returns a single response.
&lt;/li&gt;
&lt;li&gt;Frontend sees only one endpoint.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use Redis or in-memory caches to store frequently accessed, aggregated data for faster responses.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

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




&lt;h2&gt;
  
  
  6. A Phased Migration from Monolith to Microservices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  6.1 The Strangler Fig Pattern
&lt;/h3&gt;

&lt;p&gt;Gradually replace parts of the legacy monolith with new microservices, leaving the old system running until it’s safe to switch over.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  6.2 Step-by-Step Approach
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;API-Enable the Monolith&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Refactor direct DB calls into internal APIs.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect to New Services&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;As you introduce microservices, route specific functionality from the monolith to the new system.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gradual Cutover&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Retire monolith components in stages, once the new services are stable and fully tested.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  7. Summary &amp;amp; Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Apply Clean Architecture&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Keep your core business logic separate from infrastructure details with a well-defined adapter layer.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralize Common Data&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;If multiple services rely on the same data, consider a Master Data Service plus caching and fault tolerance strategies.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balance Code Duplication&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Be mindful of DRY but accept that some duplication may keep services independent and easier to maintain.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address JOIN Limitations&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Adopt patterns like CQRS or a data aggregation service to replicate the convenience of table joins without merging databases.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Migrate in Phases&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Use the Strangler Fig pattern to introduce microservices incrementally, reducing risk and ensuring steady progress.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By combining microservices with Clean Architecture, you gain a &lt;strong&gt;scalable, maintainable&lt;/strong&gt; solution that keeps &lt;strong&gt;domain logic clean&lt;/strong&gt;. While you lose the simplicity of monolithic table joins, you gain flexibility, autonomy for each service, and the potential for more robust, scalable applications over the long run.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The Clean Architecture (by Uncle Bob)&lt;/strong&gt;
&lt;a href="https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html" rel="noopener noreferrer"&gt;https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microservices Patterns (by Chris Richardson)&lt;/strong&gt;
&lt;a href="https://microservices.io/patterns/index.html" rel="noopener noreferrer"&gt;https://microservices.io/patterns/index.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strangler Fig Pattern (Martin Fowler)&lt;/strong&gt;
&lt;a href="https://martinfowler.com/bliki/StranglerFigApplication.html" rel="noopener noreferrer"&gt;https://martinfowler.com/bliki/StranglerFigApplication.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CQRS (Command Query Responsibility Segregation) – Martin Fowler&lt;/strong&gt;
&lt;a href="https://martinfowler.com/bliki/CQRS.html" rel="noopener noreferrer"&gt;https://martinfowler.com/bliki/CQRS.html&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>microservices</category>
      <category>migration</category>
      <category>cleanarchitecture</category>
    </item>
  </channel>
</rss>
