<?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>Forem: Sridhar CR</title>
    <description>The latest articles on Forem by Sridhar CR (@sridharcr).</description>
    <link>https://forem.com/sridharcr</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%2F1048049%2Fc233f2b7-59b6-4d00-853e-2a2875d73cc4.jpeg</url>
      <title>Forem: Sridhar CR</title>
      <link>https://forem.com/sridharcr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sridharcr"/>
    <language>en</language>
    <item>
      <title>Stop AI From Seeing What It Shouldn’t: A Practical Guide to PII Safety</title>
      <dc:creator>Sridhar CR</dc:creator>
      <pubDate>Sun, 16 Nov 2025 07:15:00 +0000</pubDate>
      <link>https://forem.com/sridharcr/stop-ai-from-seeing-what-it-shouldnt-a-practical-guide-to-pii-safety-38ll</link>
      <guid>https://forem.com/sridharcr/stop-ai-from-seeing-what-it-shouldnt-a-practical-guide-to-pii-safety-38ll</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;br&gt;
AI features are great, but if you feed them personal data, things can go wrong very quickly. Before your app talks to an AI model, make sure it is not accidentally sending PII.&lt;/p&gt;
&lt;h1&gt;
  
  
  We all know what PII is
&lt;/h1&gt;

&lt;p&gt;PII stands for Personally Identifiable Information. It is anything that can directly or indirectly identify a person.&lt;/p&gt;

&lt;p&gt;Names, emails, phone numbers, home addresses, government IDs, bank details, biometrics the list goes on.&lt;/p&gt;

&lt;p&gt;We deal with it every day while building products. Nothing new here.&lt;/p&gt;

&lt;p&gt;The real problem starts when we mix PII with AI features.&lt;br&gt;
The challenge isn’t that PII exists. The challenge is that AI systems eagerly consume whatever data we send them... even when they shouldn’t.&lt;/p&gt;
&lt;h1&gt;
  
  
  How PIIs can get exposed to the AI (directly or accidentally)
&lt;/h1&gt;

&lt;p&gt;There are many situations where PII slips into the AI layer without anyone meaning to do it. A few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Intelligent search&lt;/strong&gt;&lt;br&gt;
A user searches for something like "John Smith account balance 4367" and the search system forwards the full prompt to an LLM behind the scenes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data analytics&lt;/strong&gt;&lt;br&gt;
We feed big datasets into an AI model to extract insights and forget that those tables contain names, emails and other personal info.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fraud or risk detection&lt;/strong&gt;&lt;br&gt;
AI models often use IDs, location and behavioral history to detect fraud. Sometimes the pipeline ends up passing the raw data to an LLM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chatbots and customer support&lt;/strong&gt;&lt;br&gt;
Users often share private information like account numbers or home addresses in messages and those messages get forwarded to an AI agent to generate answers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Document or content summarization&lt;/strong&gt;&lt;br&gt;
Users upload resumes, invoices, medical reports or contracts, and the AI summarizer sees everything inside those documents.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all of these cases the team never &lt;em&gt;intends&lt;/em&gt; to expose PII. But it happens because the AI layer simply receives whatever data comes its way.&lt;br&gt;
And importantly: this risk applies during both &lt;strong&gt;training&lt;/strong&gt; and &lt;strong&gt;inference&lt;/strong&gt; (every time your app calls an AI API).&lt;/p&gt;
&lt;h1&gt;
  
  
  The risk of exposing PII to AI
&lt;/h1&gt;

&lt;p&gt;Here is why this gets scary fast:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AI does not forget&lt;/strong&gt;&lt;br&gt;
If a model sees PII during training or input, it might surface it later. For example, someone asks the model for sample bank fraud data and the output ends up containing a real email or phone number that it once saw.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Legal trouble&lt;/strong&gt;&lt;br&gt;
Regulations like GDPR and CCPA are very strict about how personal data is processed. If your AI feature handles PII without the right controls, you can get into real legal and financial trouble.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data exposure&lt;/strong&gt;&lt;br&gt;
Even if the model behaves correctly, logs, prompts, intermediate storage, training data and prompt history can leak personal information to the wrong place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;User trust&lt;/strong&gt;&lt;br&gt;
Once users think their private data was used in a way they did not agree to, trust is gone. Sometimes permanently.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;
  
  
  How to prevent it
&lt;/h1&gt;

&lt;p&gt;Here are practical ways to stop PII from reaching your AI model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Safest option: do not send PII to AI&lt;/strong&gt;&lt;br&gt;
If the task does not need personal info, strip it out. Replace names with IDs, or anonymize the entire dataset before doing any AI processing. This is often impractical though.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mask, redact or remove PII&lt;/strong&gt;&lt;br&gt;
If the data items are much simpler (for example, Indian phone numbers only), regex can sometimes be enough. But if the scenario is open-ended, tools like Presidio or NER-based models help detect names, emails, phone numbers and other identifiers before sending the text or dataset to the AI model.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can mask values (e.g. joh***@gmail.com), replace them with placeholders, or delete them completely.&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%2Fvkpx83sxz6wdct3e07f3.gif" 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%2Fvkpx83sxz6wdct3e07f3.gif" alt=" " width="720" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s a quick code example using Presidio:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;presidio_analyzer&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnalyzerEngine&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;presidio_anonymizer&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnonymizerEngine&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;presidio_analyzer.nlp_engine&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SpacyNlpEngine&lt;/span&gt;

&lt;span class="c1"&gt;# --- Initialize Presidio ---
&lt;/span&gt;&lt;span class="n"&gt;nlp_engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SpacyNlpEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&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;en&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;en_core_web_lg&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;analyzer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnalyzerEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nlp_engine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;nlp_engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;supported_languages&lt;/span&gt;&lt;span class="o"&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;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;anonymizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnonymizerEngine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# --- Input text ---
&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;My name is John Doe, my email is john.doe@example.com and my phone number is +1-202-555-0170.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# --- Detect PII ---
&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;analyzer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;en&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# --- Mask PII ---
&lt;/span&gt;&lt;span class="n"&gt;anonymized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anonymizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anonymize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;analyzer_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;anonymizers&lt;/span&gt;&lt;span class="o"&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;DEFAULT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;type&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;mask&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Original:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Anonymized:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;anonymized&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Original: My name is John Doe, my email is john.doe@example.com and my phone number is +1-202-555-0170.
Anonymized: My name is **********, my email is ********************** and my phone number is *******************
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once masking or redaction is in place, the next step is to ensure the AI only receives the minimum amount of information it needs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data minimization&lt;/strong&gt;&lt;br&gt;
Only send the data that is absolutely necessary. Most AI features do not need full user profiles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Add guardrails to AI inputs and outputs&lt;/strong&gt;&lt;br&gt;
Scan incoming user prompts for PII and block or redact them.&lt;br&gt;
Also scan AI responses to make sure the model is not trying to output PII back to the user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Secure logs and storage&lt;/strong&gt;&lt;br&gt;
If you store prompts, chat messages or training data that might contain PII, add access controls and deletion policies.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  How the industry handles it
&lt;/h1&gt;

&lt;p&gt;Big AI platforms are already aware of this problem and are adding safety layers.&lt;/p&gt;

&lt;p&gt;For example, &lt;strong&gt;OpenAI Agent Builder&lt;/strong&gt; has built-in guardrails that detect and redact PII from both inputs and outputs. &lt;/p&gt;

&lt;p&gt;It combines rule-based techniques and AI detection to catch things like names, addresses, emails and financial details before the model sees them or before the model tries to return them.&lt;/p&gt;

&lt;p&gt;There are also popular open source tools such as &lt;strong&gt;Microsoft Presidio&lt;/strong&gt;, which many companies use to scan and mask PII before running analytics or AI workloads.&lt;/p&gt;

&lt;p&gt;The pattern is the same across the industry:&lt;br&gt;
&lt;strong&gt;Detect PII early, remove or protect it, then use AI.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These systems are not perfect, but they reflect one clear lesson: privacy cleanup must happen &lt;em&gt;before&lt;/em&gt; the AI sees the data, not after.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;If you are an entrepreneur, a developer or someone excited about adding AI features to your product, here is the simple takeaway:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Make your app smarter, but do not make it reckless.&lt;br&gt;
Handle PII before the data reaches the AI layer.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is always easier to prevent a privacy issue than to fix one after damage has been done.&lt;/p&gt;

&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Microsoft Presidio – Data Protection and De-identification SDK&lt;br&gt;
&lt;a href="https://microsoft.github.io/presidio/" rel="noopener noreferrer"&gt;https://microsoft.github.io/presidio/&lt;/a&gt;&lt;br&gt;
(Microsoft GitHub)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“Implementing Text PII Anonymization” – Arize AI blog&lt;br&gt;
&lt;a href="https://arize.com/blog/pii-removal-microsoft-presidio-chatbot/" rel="noopener noreferrer"&gt;https://arize.com/blog/pii-removal-microsoft-presidio-chatbot/&lt;/a&gt;&lt;br&gt;
(Arize AI)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“Enhancing the De-identification of Personally Identifiable Information in Educational Data”&lt;br&gt;
Y. Shen et al., Jan 2025&lt;br&gt;
&lt;a href="https://arxiv.org/abs/2501.09765" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2501.09765&lt;/a&gt;&lt;br&gt;
(arXiv)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;“Proactive Privacy Amnesia for Large Language Models: Safeguarding PII with Negligible Impact on Model Utility”&lt;br&gt;
Martin Kuo et al., Feb 2025&lt;br&gt;
&lt;a href="https://arxiv.org/abs/2502.17591" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2502.17591&lt;/a&gt;&lt;br&gt;
(arXiv)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>data</category>
      <category>infosec</category>
    </item>
    <item>
      <title>How to Migrate Massive Data in Record Time—Without a Single Minute of Downtime 🕑</title>
      <dc:creator>Sridhar CR</dc:creator>
      <pubDate>Fri, 13 Dec 2024 17:26:22 +0000</pubDate>
      <link>https://forem.com/sridharcr/how-to-migrate-massive-data-in-record-time-without-a-single-minute-of-downtime-113g</link>
      <guid>https://forem.com/sridharcr/how-to-migrate-massive-data-in-record-time-without-a-single-minute-of-downtime-113g</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Imagine you're working at one of the biggest enterprise multitenant SaaS platform. Everything is moving at lightning speed—new data is pouring in, orders are flowing from multiple channels, and your team is constantly iterating on new features. But there's one problem: your data infrastructure, built on MongoDB, is becoming a bottleneck.&lt;/p&gt;

&lt;p&gt;While MongoDB serves well for operational data, it's struggling to handle the complexity of modern data analytics, aggregations, and transformations. Running advanced queries or performing complex analytics is becoming increasingly difficult.&lt;/p&gt;

&lt;p&gt;To stay competitive, your team is planning a migration to an HTAP (Hybrid Transactional/Analytical Processing) SQL database—one that can seamlessly support both OLTP (Online Transaction Processing) and OLAP (Online Analytical Processing) workloads. The challenge? Zero downtime is non-negotiable. Disrupting customer operations or compromising data integrity during migration simply isn't an option.&lt;/p&gt;

&lt;p&gt;Keep reading to discover how I solved this challenge and ensured a seamless migration based on my experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Researching Market Tools
&lt;/h2&gt;

&lt;p&gt;There are numerous tools for ETL, and readily available options like Airbyte can help move data between databases. However, in this case, you're migrating from NoSQL to SQL, including data transformations to normalize the data. After some analysis, I decided to go with Apache Spark.&lt;/p&gt;

&lt;p&gt;Apache Spark is known for its speed, scalability, and ability to handle massive datasets. But the real question is: how do you leverage Spark to ensure a fast, efficient ETL process that migrates your data without disrupting business operations?&lt;/p&gt;

&lt;h2&gt;
  
  
  Design and Architecture
&lt;/h2&gt;

&lt;p&gt;To achieve zero downtime migration, I broke down the task into two key components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Migration Phase: Moving the initial bulk of data to the new system.&lt;/li&gt;
&lt;li&gt;Live Sync Phase: Ensuring continuous synchronization between the old and new systems during and after the migration.
By designing these two phases carefully and coupling them with a timeline approach, I ensured a seamless, uninterrupted transition.&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%2Fwzmf8ks3rn7b71xuz9z8.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%2Fwzmf8ks3rn7b71xuz9z8.png" alt="Image description" width="800" height="273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Migration Phase: Lifting the Bulk Data&lt;/strong&gt;&lt;br&gt;
The Migration Phase focuses on transferring large volumes of historical data from the source database to the target system efficiently. The goal is to move the majority of the data in one go, with minimal impact on ongoing business operations.&lt;/p&gt;

&lt;p&gt;During this phase, Spark handles the heavy lifting. Instead of performing the migration sequentially—something that could take days or weeks for large datasets—Spark divides the data into smaller chunks called partitions. Each partition is processed in parallel across multiple worker nodes in the Spark cluster, speeding up the migration process significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Sync Phase: Syncing the Continuous Data&lt;/strong&gt;&lt;br&gt;
While the Migration Phase focuses on transferring bulk historical data, the Live Sync Phase ensures that any ongoing changes to the data in the source database are continuously reflected in the target database in real-time. This phase keeps both systems in sync during migration and handles inserts, updates, and deletes without downtime.&lt;/p&gt;

&lt;p&gt;By relying on real-time data processing, I ensured that new data was continuously migrated, without interrupting business operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallelism—The Secret to Speed and Efficiency
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Level 1: Spark’s Native Parallelism&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At the heart of Spark’s power is its ability to partition and process data in parallel across multiple nodes. By splitting large datasets into smaller partitions, Spark handles each partition independently, dramatically speeding up the entire ETL process. Spark’s built-in parallelism handles the distribution of data automatically, ensuring optimal performance without micromanaging the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Level 2: Custom Parallelism—Scaling with Multiple Spark Clusters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If the workload is too large for a single cluster to handle efficiently, custom parallelism comes into play. By running multiple Spark clusters in parallel, I was able to distribute the workload across different clusters, each processing a subset of the data. This horizontal scaling significantly improved performance, allowing me to manage even larger datasets across distributed environments.&lt;/p&gt;

&lt;p&gt;In this setup, each Spark cluster operates independently, but they are orchestrated to maintain a smooth and efficient migration process. By customizing parallelism, I was able to maximize available resources, ensuring no single cluster became overwhelmed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Monitoring and Safeguarding the Migration
&lt;/h2&gt;

&lt;p&gt;To ensure a smooth, error-free migration, I designed read, write operations, and data transformations as individual action classes, each adhering to the Single Responsibility Principle. This modular approach made it easy to manage and extend the migration pipeline. I used Finite State Automata (FSA) to track the various stages of the migration, from data extraction to transformation and loading, ensuring that each step was executed in sequence and errors could be quickly pinpointed.&lt;/p&gt;

&lt;p&gt;Error tracking was integrated into every action class, with granular logging to capture failures at specific points, making it easy to troubleshoot and recover. I also implemented regular checkpoints, which allowed me to resume the migration from the last successful point in case of failure, minimizing downtime and reprocessing. Additionally, I continuously monitored performance to track execution times, resource usage, and error rates, helping to optimize the pipeline and ensure everything ran smoothly throughout the migration.&lt;/p&gt;

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

&lt;p&gt;As I reflect on the journey, it’s clear: Apache Spark was the true hero of the migration. From enabling efficient ETL processes with parallelism to ensuring zero downtime migration, Spark transformed the way our company handles data.&lt;/p&gt;

&lt;p&gt;With Spark, I’ve learned that scalability, speed, and reliability don’t have to be mutually exclusive. Most importantly, I’ve unlocked the ability to migrate and transform data without ever missing a beat.&lt;/p&gt;




&lt;p&gt;Are you ready to revolutionize your ETL workflows with Spark? Whether you're migrating data or building a real-time data pipeline, Spark’s power can help you achieve the performance, scalability, and reliability your business needs.&lt;/p&gt;

&lt;p&gt;Feel free to share your experiences, ask questions, or let me know how you've used Apache Spark for your ETL processes. Let’s continue the conversation!&lt;/p&gt;

</description>
      <category>etl</category>
      <category>spark</category>
      <category>database</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>Boost Your Redis-Powered Caching: Unleashing the Magic of Efficient Data Serialization</title>
      <dc:creator>Sridhar CR</dc:creator>
      <pubDate>Tue, 10 Oct 2023 13:13:10 +0000</pubDate>
      <link>https://forem.com/sridharcr/boost-your-redis-powered-caching-unleashing-the-magic-of-efficient-data-serialization-l13</link>
      <guid>https://forem.com/sridharcr/boost-your-redis-powered-caching-unleashing-the-magic-of-efficient-data-serialization-l13</guid>
      <description>&lt;p&gt;In the quest to optimize application performance, caching is often the go-to strategy. However, many popular standalone caching solutions like &lt;strong&gt;Redis&lt;/strong&gt; and &lt;strong&gt;Memcached&lt;/strong&gt; primarily deal with string data. Consequently, data originating from the application must be converted into string format before it's pushed into the cache. This process essentially requires data serialization for storage.&lt;/p&gt;

&lt;p&gt;Even with various caching strategies like Cache-Aside, Write-Through, Write-Behind, or Read-Through, the fundamental requirement remains the same: reading and writing data to and from the cache. When retrieving data from the cache, the application is faced with the task of deserialization, converting the stored string back into its original data format. It's important to note that this serialization and deserialization process can consume a significant amount of time, with the time required directly linked to the size of the data.&lt;/p&gt;

&lt;p&gt;Thankfully, there are alternative methods for serializing data that don't involve converting it to JSON. One such approach is the use of &lt;strong&gt;Messagepack standards&lt;/strong&gt;. Messagepack offers the advantage of efficient data storage and significantly faster data serialization. Find more about &lt;a href="https://msgpack.org/index.html" rel="noopener noreferrer"&gt;messagepack&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A simple representation of how messagepack stores the data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fder79tuke6fyryu8r3y8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fder79tuke6fyryu8r3y8.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of messagepack:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Efficiency&lt;/strong&gt;: MessagePack is a binary serialization format, whereas JSON is a text-based format. This means MessagePack typically requires less space to represent the same data, resulting in smaller message sizes. Smaller payloads can lead to reduced network and storage usage, which can be especially important in resource-constrained environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Speed&lt;/strong&gt;: Due to its binary nature, MessagePack is faster to encode (serialize) and decode (deserialize) compared to JSON. This speed advantage is particularly beneficial in applications where rapid data serialization and deserialization are crucial for performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Compatibility&lt;/strong&gt;: MessagePack is designed to be language-agnostic, and there are libraries available for a wide range of programming languages. This makes it easier to work with MessagePack in a multi-language or multi-platform environment, where different components of an application may be written in different languages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Native Data Types&lt;/strong&gt;: MessagePack includes native support for a wide range of data types, including integers, floats, strings, arrays, and maps. This can lead to more efficient and accurate serialization and deserialization of data, especially when dealing with complex or nested data structures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-Platform&lt;/strong&gt;: MessagePack's binary format makes it suitable for cross-platform data exchange. It can be used to transmit data between different systems and architectures without compatibility issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backward and Forward Compatibility&lt;/strong&gt;: MessagePack provides a level of backward and forward compatibility. New fields or data types can be added to your MessagePack messages without breaking compatibility with older versions of your software. This flexibility is valuable when working with evolving data schemas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reduced Overhead&lt;/strong&gt;: JSON includes metadata and human-readable keys, which add overhead to the data. MessagePack, being a binary format, eliminates much of this overhead, resulting in more compact data representation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Streaming Support&lt;/strong&gt;: MessagePack is well-suited for streaming data, as you can serialize and deserialize data incrementally. This is particularly useful for scenarios like real-time data processing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Binary Data Handling&lt;/strong&gt;: MessagePack is excellent for handling binary data, such as images or serialized objects, as it doesn't require escaping or encoding of binary characters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ecosystem&lt;/strong&gt;: MessagePack has a growing ecosystem of libraries and tools that support it, making it easier to integrate into your existing applications and infrastructure.&lt;/p&gt;

&lt;p&gt;One of the noteworthy feature of Messagepack is its compatibility with a wide range of programming languages. In this post, we will explore Messagepack's performance benefits by using Python to serialize a Python dictionary with Messagepack tools and compare this performance to JSON. We conducted benchmark tests with a 70KB JSON data loaded as a dictionary.&lt;/p&gt;

&lt;p&gt;With Messagepack tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Serialization is approximately &lt;strong&gt;4 times faster&lt;/strong&gt; compared to JSON.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deserialization is around &lt;strong&gt;1.2 times faster&lt;/strong&gt; than with JSON.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;msgpack&lt;/span&gt;

&lt;span class="c1"&gt;# Replace your data in 'dict_70_kb'
&lt;/span&gt;&lt;span class="n"&gt;nonserialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dict_70_kb&lt;/span&gt;

&lt;span class="c1"&gt;# Serializer methods
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;json_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;json_serialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json_serialized_dict_70kb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;msgpack_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;msgpack_serialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msgpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;msgpack_serialized_dict_70kb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;msgpack_pack_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;msgpack_serialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msgpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;packb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;msgpack_serialized_dict_70kb&lt;/span&gt;

&lt;span class="c1"&gt;# Deserializer methods
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;json_deserializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;deserialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deserialized_dict_70kb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;msgpack_deserializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;deserialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msgpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deserialized_dict_70kb&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;msgpack_pack_deserializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;deserialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;msgpack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unpackb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deserialized_dict_70kb&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;JSON serialization: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="nf"&gt;json_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonserialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Msgpack serialization: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="nf"&gt;msgpack_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonserialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Msgpack pack serialization: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="nf"&gt;msgpack_pack_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonserialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;json_serialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;json_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonserialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;msgpack_serialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;msgpack_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonserialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;msgpack_pack_serialized_dict_70kb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;msgpack_pack_serializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nonserialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;JSON deserialization: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="nf"&gt;json_deserializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json_serialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Msgpack deserialization: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="nf"&gt;msgpack_deserializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msgpack_serialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Msgpack pack deserialization: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="n"&gt;timeit&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt; &lt;span class="nf"&gt;msgpack_pack_deserializer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msgpack_pack_serialized_dict_70kb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here's the python's time benchmarks, with huge number of iterations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON Serialization - Conversion to JSON&lt;/li&gt;
&lt;li&gt;Messagepack Serialization and Messagepack pack Serialization (both are same) - Conversion to Binary Messagepack&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;same info applies to the deserialization as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fd4g20d3hjjz343aqig3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fd4g20d3hjjz343aqig3l.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A simple scatterplot to display the difference between different strategies.&lt;br&gt;
&lt;a href="https://media.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%2Fuwkvp6zovpcys9jdnghb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fuwkvp6zovpcys9jdnghb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try using messagepack in your application and check the performance benchmarks. Let me know if you have any questions or difficulties with messagepack.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>cache</category>
      <category>backend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Enhancing Code Quality and Security: Building a Rock-Solid CI Test Suite for Seamless Development</title>
      <dc:creator>Sridhar CR</dc:creator>
      <pubDate>Mon, 03 Jul 2023 16:14:03 +0000</pubDate>
      <link>https://forem.com/sridharcr/enhancing-code-quality-and-security-building-a-rock-solid-ci-test-suite-for-seamless-development-1ld0</link>
      <guid>https://forem.com/sridharcr/enhancing-code-quality-and-security-building-a-rock-solid-ci-test-suite-for-seamless-development-1ld0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In today's rapidly evolving software development landscape, ensuring code quality and security is of paramount importance. Continuous Integration (CI) has become an essential practice in software development, enabling developers to integrate their code changes frequently and detect issues early in the development lifecycle. One crucial aspect of CI is the test suite, which encompasses various checks to ensure code quality and security. In this blog post, we will explore the pipeline of a CI test suite for a python project, highlighting the different steps involved and the tools utilized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; Here's an quick overview of CI suite with a wide variety of steps with different tools.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--axEwdKfo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c4f9tl665fm1swno7g4j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--axEwdKfo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c4f9tl665fm1swno7g4j.jpg" alt="Image description" width="800" height="840"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Code formatting
&lt;/h2&gt;

&lt;p&gt;Consistent code formatting is vital for maintainability and collaboration within a development team. To enforce a consistent coding style, the first step in the CI test suite is code formatting. There are lots of code formatters available such as,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Black&lt;/li&gt;
&lt;li&gt;autopep8&lt;/li&gt;
&lt;li&gt;yapf&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Black&lt;/strong&gt; is a popular Python code formatter that automatically reformats code to adhere to a defined style guide. By integrating Black into the CI pipeline, developers can ensure that their code follows consistent formatting conventions, enhancing readability and reducing code review overhead.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LY5rviO---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9aop6fvu0samjhb94h35.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LY5rviO---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9aop6fvu0samjhb94h35.png" alt="Image description" width="800" height="102"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Code linting
&lt;/h2&gt;

&lt;p&gt;Linting is another crucial aspect of code quality. It helps to enforce the best practices and identifies common pitfalls, improving the overall code quality. Some of the commonly used code linters are as follows,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pylint&lt;/li&gt;
&lt;li&gt;Sonarlint (does more than linting)&lt;/li&gt;
&lt;li&gt;flake8&lt;/li&gt;
&lt;li&gt;autopep8 &lt;/li&gt;
&lt;li&gt;bandit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Pylint&lt;/strong&gt;, a widely used Python static code analyzer, performs lint checks to identify potential programming errors, stylistic issues, and adherence to coding standards. Integrating Pylint into the CI test suite ensures that code is thoroughly analyzed for potential issues before merging into the main codebase.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kDrI3N6y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d29rvmcpz3vif7ob42rz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kDrI3N6y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d29rvmcpz3vif7ob42rz.png" alt="Image description" width="800" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Code vulnerability checks
&lt;/h2&gt;

&lt;p&gt;In an era where security threats are prevalent, it is essential to detect vulnerabilities and security hotspots in the codebase. Various tools for these checks are,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sonarqube (sonarlint + other checks)&lt;/li&gt;
&lt;li&gt;cycode&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sonarqube, a code analysis tool, performs static security analysis to identify potential security vulnerabilities, such as insecure authentication mechanisms or code that is susceptible to injection attacks. By integrating Sonarqube into the CI pipeline, developers can proactively identify and address security issues, reducing the risk of potential exploits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4UUMJNmX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uoa7h6ddt0hqk3yn4ueh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4UUMJNmX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uoa7h6ddt0hqk3yn4ueh.png" alt="Image description" width="800" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Unit test cases
&lt;/h2&gt;

&lt;p&gt;Unit testing is a fundamental practice in software development to validate the correctness of individual code units or components. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--enCnF9Ge--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umbuydlo6yaz2d1lpf9k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--enCnF9Ge--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umbuydlo6yaz2d1lpf9k.png" alt="Image description" width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Scenario test cases
&lt;/h2&gt;

&lt;p&gt;Beyond unit tests, scenario or integration tests provide end-to-end validation of the system's behavior. &lt;br&gt;
&lt;strong&gt;Behave&lt;/strong&gt;, a popular Behavior-Driven Development (BDD) framework for Python, allows developers to define test scenarios in a human-readable format. These scenarios describe the expected behavior of the system from a user's perspective. By including scenario test cases in the CI test suite, developers can ensure that the software functions correctly in real-world scenarios and that different components interact seamlessly.&lt;/p&gt;

&lt;p&gt;When connected with a reporting tool known as &lt;strong&gt;allure&lt;/strong&gt;, we can checks the results in an interactive UI,&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SAKoe5CF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y481dhjs562xv9dchp86.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SAKoe5CF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y481dhjs562xv9dchp86.png" alt="Image description" width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: Code coverage benchmarks
&lt;/h2&gt;

&lt;p&gt;For section of testing, the coverage benchmarks should be addressed thoroughly. For both unit tests and scenario tests, having a strict coverage percents, helps the development to address and write testcases for the boundary conditions/edge cases. It provides the confidence of unit tests and how much of the code has been tested.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q4izmF_o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xuxjfxcdg5uckk8x7jc6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q4izmF_o--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xuxjfxcdg5uckk8x7jc6.png" alt="Image description" width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 7: AppSec Checks
&lt;/h2&gt;

&lt;p&gt;The security plays a vital role in the development lifecycle. Each section of the security checks can be covered in the pipeline. They include the image scans and DAST. &lt;/p&gt;

&lt;p&gt;The image scanning can be done with various scanning tools such as,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Clair (also being used in ECR)&lt;/li&gt;
&lt;li&gt;Trivy&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tools like Clair provide image scanning capabilities that analyze the container image for known vulnerabilities and adherence to security best practices. Integrating Clair image scan checks into the CI pipeline allows developers to identify and address any security issues before deploying containerized applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Rx5mX-qB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n84t831elntqlposrhmj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Rx5mX-qB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n84t831elntqlposrhmj.png" alt="Image description" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The DAST checks can be automated up to a certain point, where the code should be able to withstand certain scans and attacks. For eg. SQL Injections can be checked with &lt;a href="https://github.com/sqlmapproject/sqlmap"&gt;sqlmap&lt;/a&gt; which tests with each and every type of sql injection payload and reports it back to the user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YbUMAtCB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/14q196ybzpni21jgd9sd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YbUMAtCB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/14q196ybzpni21jgd9sd.png" alt="Image description" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;A strict pipeline of a CI test suite provides a comprehensive approach to ensure code quality and security throughout the software development process. By incorporating code formatting checks, linting, security analysis, unit tests, scenario tests, and image scans, developers can mitigate potential issues early on and deliver robust and secure software.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>ci</category>
      <category>development</category>
      <category>python</category>
    </item>
    <item>
      <title>The Ultimate Guide to Web Application Security (As a developer)</title>
      <dc:creator>Sridhar CR</dc:creator>
      <pubDate>Fri, 28 Apr 2023 20:10:55 +0000</pubDate>
      <link>https://forem.com/sridharcr/the-ultimate-guide-to-web-application-security-as-a-developer-26d9</link>
      <guid>https://forem.com/sridharcr/the-ultimate-guide-to-web-application-security-as-a-developer-26d9</guid>
      <description>&lt;p&gt;In this era of digital information, web security is one of the crucial aspects of the web apps. Due to their wide spread availability and accessibility, web applications are vulnerable to a variety of attacks, such as cross-site scripting (XSS), SQL injection, and file inclusion attacks.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A bug was reported to LinkedIn, regarding the issue which allowed users to delete any published content that was not even published by that specific user.&lt;br&gt;
It is a classic example of access control issue&lt;br&gt;
&lt;a href="https://www.moneycontrol.com/news/business/indian-hacker-found-bug-that-could-have-led-to-deletion-of-any-linkedin-posts-10451971.html"&gt;Click here&lt;/a&gt; to read more...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To ensure web application security, it's essential to implement various measures inorder to build a safe and secure web application. I have listed down the crucial measures that are build safe web apps. Let's go over each concepts and understand how it helps to reach our goal.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Authentication and Authorization
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Authentication&lt;/strong&gt; is the act of validating that users are whom they claim to be. This is the first step in any security process. &lt;/p&gt;

&lt;p&gt;The authentication can be implemented with various methods based on the needs of the application, it can be as simple as &lt;strong&gt;OAuth with JWT tokens&lt;/strong&gt; or it can involve SSO with &lt;strong&gt;OpenID Connect&lt;/strong&gt;, &lt;strong&gt;SAML&lt;/strong&gt;, etc. A strict authentication process would be an absolute neccessity for building secure apps.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Authorization&lt;/strong&gt; is the process of giving the user permission to access a specific resource or function. This term is often used interchangeably with access control or client privilege.&lt;/p&gt;

&lt;p&gt;The means of access control is highly coupled with the business needs. The &lt;strong&gt;Object Level authorization&lt;/strong&gt; would also be an absolute neccessity for our goal. An ideal access control should be have an resource level (API level) privileges &lt;code&gt;\products&lt;/code&gt; and as well as data access level privileges with different write, read access. &lt;/p&gt;

&lt;h3&gt;
  
  
  2. HTTPS (SSL/TLS) and Data Security
&lt;/h3&gt;

&lt;p&gt;Secure REST services must only provide HTTPS endpoints. This protects authentication credentials in transit, for example passwords, API keys or JSON Web Tokens. It also allows clients to authenticate the service and guarantees integrity of the transmitted data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nHQIAgTq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yh4lk925szccrzrnoidm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nHQIAgTq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yh4lk925szccrzrnoidm.png" alt="Image description" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sensitive data should be stored properly by employing various techniques such as &lt;strong&gt;encryption, hashing&lt;/strong&gt;, etc. For example, the password hash can be stored instead of storing the actual password. The encryption keys, hash keys and salts should be stored safely and should not be revealed under any circumstances.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Input data Validation
&lt;/h3&gt;

&lt;p&gt;The input payloads of the API should be promptly validated before the actual execution of the API. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not trust input parameters/objects.&lt;/li&gt;
&lt;li&gt;Validate input: length / range / format and type.&lt;/li&gt;
&lt;li&gt;Achieve an implicit input validation by using strong types like numbers, booleans, dates, times or fixed data ranges in API parameters.&lt;/li&gt;
&lt;li&gt;Constrain string inputs with regexps.&lt;/li&gt;
&lt;li&gt;Reject unexpected/illegal content.&lt;/li&gt;
&lt;li&gt;Make use of validation/sanitation libraries or frameworks in your specific language.&lt;/li&gt;
&lt;li&gt;Define an appropriate request size limit and reject requests exceeding the limit with HTTP response status 413 Request Entity Too Large.&lt;/li&gt;
&lt;li&gt;Consider logging input validation failures. Assume that someone who is performing hundreds of failed input validations per second is up to no good.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Security headers
&lt;/h3&gt;

&lt;p&gt;There are a number of security related headers that can be returned in the HTTP responses to instruct browsers to act in specific ways. However, some of these headers are intended to be used with HTML responses, and as such may provide little or no security benefits on an API that does not return HTML.&lt;/p&gt;

&lt;p&gt;The following headers should be included in all API responses:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DgMZ128i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g1p68wkkabc3kfu8ur27.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DgMZ128i--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g1p68wkkabc3kfu8ur27.png" alt="Security headers info" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These headers are highly configurable, so make use of this flexibility to allow the least privileges that are required for the users.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Cookie security
&lt;/h3&gt;

&lt;p&gt;There are several use cases where we use cookies to store relevant information, such as session, tokens, CSRF tokens, etc. In order to enforce the cookie security, we have several attributes which can be set. They are listed as follows,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XNfdFEkw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o8z38d76zz582jg01qav.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XNfdFEkw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o8z38d76zz582jg01qav.png" alt="Cookie security info" width="800" height="113"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Error handling
&lt;/h3&gt;

&lt;p&gt;We should be using classic error mapping techniques show an generic error messages to client. We should be avoiding detailed techincal information such as tracebacks, sql errors, system errors, etc. &lt;/p&gt;

&lt;p&gt;If an error occurred based on the input payload, then we can raise a custom generic message such as &lt;code&gt;HTTP 400 - Bad Request&lt;/code&gt; or &lt;code&gt;HTTP 500 - Internal Server Error&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Audit logs
&lt;/h3&gt;

&lt;p&gt;Write audit logs before and after security related events. Consider logging token validation errors in order to detect attacks. Take care of log injection attacks by sanitizing log data beforehand.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Up-to date images and libraries
&lt;/h3&gt;

&lt;p&gt;As in the microservices era, we would be using docker images from public repositories and we also install the required packages. The outdated versions of utils/libraries would create a potential vulnerability that waits to be exploited. Hence we need to take care of these issues as well. &lt;/p&gt;

&lt;p&gt;This is not a one time activity, new bugs/issues would always pop in and we need to routinely check and resolve these kinds of issues. There are lots of scanners available as open source in the market, figure out the best tool that suits for the application and get to know about these types of vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kn-rT_Uk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32mkdndowdh3vrw297o2.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kn-rT_Uk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/32mkdndowdh3vrw297o2.PNG" alt="Image description" width="761" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a good scanner, &lt;strong&gt;Clair - Vulnerability Static Analysis for containers&lt;/strong&gt; - &lt;a href="https://github.com/quay/clair"&gt;Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By strictly following all these approaches, we should be able to build a secure web application. This should be able to fend of possible attacks if it is hosted in a secure network behind the firewall. Even though we employ all these techniques to create a safe systems, the responsibility equally boils down on the developers who has to write the code without any bugs.&lt;/p&gt;

&lt;p&gt;THANK YOU FOR READING&lt;br&gt;
I hope you found this little article helpful. Please share it with your friends and colleagues. Sharing is caring. Connect with me on &lt;a href="https://www.linkedin.com/in/sridharcr/"&gt;LinkedIn&lt;/a&gt; to read more about Python, Architecture design, Security, and more…!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>api</category>
      <category>cybersecurity</category>
    </item>
    <item>
      <title>Why consistency and availability cannot coexist in distributed systems?</title>
      <dc:creator>Sridhar CR</dc:creator>
      <pubDate>Sun, 26 Mar 2023 17:25:24 +0000</pubDate>
      <link>https://forem.com/sridharcr/why-consistency-and-availability-cannot-coexist-in-distributed-systems-297</link>
      <guid>https://forem.com/sridharcr/why-consistency-and-availability-cannot-coexist-in-distributed-systems-297</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Have you ever pondered why consistency and availability cannot coexist in distributed systems, as the title suggests?&lt;/p&gt;

&lt;p&gt;While it may be achievable in a single server mode, it could be considered a single point of failure, therefore making availability uncertain. In distributed systems, with multiple partitions, attaining both consistency and availability is not feasible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_v4AkzKa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpg6vxuxsefi7guz46rb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_v4AkzKa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpg6vxuxsefi7guz46rb.jpg" alt="Image description" width="250" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CAP theorem
&lt;/h2&gt;

&lt;p&gt;CAP theorem, also known as Brewer's theorem, is an essential concept in distributed computing that explains the trade-offs involved in building a distributed system. It was introduced by Eric Brewer in 2000, and it is still relevant today in the development of modern distributed systems.&lt;/p&gt;

&lt;p&gt;The CAP theorem states that it is impossible to achieve all three of the following guarantees in a distributed system simultaneously:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Consistency:&lt;/strong&gt; All nodes in the system see the same data at the same time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Availability:&lt;/strong&gt; Every request made to the system gets a response, without guarantee of the freshness of the data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Partition tolerance:&lt;/strong&gt; The system continues to function even when network partitions occur.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DUdv1FJ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zr5j652e4fc72mzb7279.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DUdv1FJ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zr5j652e4fc72mzb7279.jpg" alt="Image description" width="880" height="862"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The theorem's fundamental idea is that a distributed system can provide at most two of these three guarantees at any given time. In other words, we have to make a trade-off between consistency, availability, and partition tolerance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistency&lt;/strong&gt; means that all nodes in the distributed system see the same data at the same time. Achieving consistency is essential for many applications where data accuracy is critical. However, ensuring consistency can be challenging in a distributed system, especially when multiple nodes try to update the same data simultaneously.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;C in CAP is different than the C in ACID. CAP-C means that data is consistent across all the nodes.ACID-C denotes the data correctness at the database level. However both denotes consistency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Availability&lt;/strong&gt; means that every request made to the system gets a response, but it doesn't guarantee the freshness of the data. If a node cannot respond to a request, the system is considered unavailable. In some cases, it may be acceptable to serve stale data, but in others, it may not be.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Partition tolerance&lt;/strong&gt; refers to the ability of a distributed system to continue functioning when communication between nodes is disrupted. A network partition occurs when a group of nodes becomes disconnected from the rest of the system due to a network failure or other issues. Partition tolerance is essential for the system to continue operating in such situations.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use-cases
&lt;/h2&gt;

&lt;p&gt;The CAP theorem tells us that in a distributed system, we have to choose between consistency and availability while ensuring partition tolerance. In reality, different applications have different requirements and priorities, and there is no one-size-fits-all solution. The choice of which two guarantees to provide depends on the application's specific needs, the scale of the system, and the potential impact of network partitions.&lt;/p&gt;

&lt;p&gt;For example, a system that handles financial transactions must prioritize consistency to ensure that all transactions are accurate and complete. On the other hand, a social media platform can prioritize availability to ensure that users can access the platform even during network disruptions, even if it means serving stale data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advancing solutions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Eventual consistency&lt;/strong&gt;&lt;br&gt;
It is nothing but a version of consistency model used in distributed systems, where all updates made to a data store will eventually be propagated to all replicas or nodes in the system, resulting in a consistent state over time. It is a weak form of consistency that allows for temporary inconsistencies or conflicts in the data until all updates are fully propagated across all nodes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Consensus algorithms&lt;/strong&gt;&lt;br&gt;
A consensus algorithm is a distributed computing protocol that enables a group of nodes or processes to agree on a single value or decision, even if some of the nodes fail or behave maliciously. It is an algorithm to achieve consistent data across all nodes, in fact, they're backbone for the blockchain applications as well.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Hybrid architecture&lt;/strong&gt;&lt;br&gt;
For database design, with the idea of CAP theorem, the architect can make informed decisions such that, the strong consistency can be applied to critical data, and would give weak consistency to non-critical data.&lt;/p&gt;

&lt;p&gt;This problem exists for around 2 decades, yet there are no ideal solutions to fix this completely. Let me know if there are new approaches that is able to solve this problem.&lt;/p&gt;

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

&lt;p&gt;The CAP theorem is a critical concept in distributed systems that highlights the trade-offs involved in building such systems. While we cannot have all three guarantees of consistency, availability, and partition tolerance simultaneously, understanding the theorem's implications can help us make informed decisions when building distributed systems.&lt;/p&gt;

</description>
      <category>database</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Design architecture for large file downloads</title>
      <dc:creator>Sridhar CR</dc:creator>
      <pubDate>Sun, 19 Mar 2023 18:27:17 +0000</pubDate>
      <link>https://forem.com/sridharcr/design-architecture-for-large-file-downloads-1ojn</link>
      <guid>https://forem.com/sridharcr/design-architecture-for-large-file-downloads-1ojn</guid>
      <description>&lt;h2&gt;
  
  
  Situation
&lt;/h2&gt;

&lt;p&gt;You are tasked with implementing a feature that allows users to download a massive CSV file, weighing in at 10 GB. The data must be sourced from a database, undergoes necessary transformations, and is served to the user as a downloadable file that should start immediately upon selecting the download option.&lt;/p&gt;

&lt;p&gt;It's important to note that the data is subject to change at regular intervals and users may not always require a download, so it's not feasible to pre-push the data to S3. Instead, this process needs to be available on-demand to ensure timely and efficient delivery of the necessary data to users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F5i7uv7o4ca90u2v0l1hi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F5i7uv7o4ca90u2v0l1hi.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution - TL;DR
&lt;/h2&gt;

&lt;p&gt;In order to handle this sitution effectively, one can opt in for the &lt;strong&gt;Streaming data from API&lt;/strong&gt; since it provides us the lot of technical advantages yet so simple. This is one of the best solution for this usecase. It provides a great deal of user experience, since the download in this approch starts instantaneously. &lt;/p&gt;

&lt;h2&gt;
  
  
  Common problems with naive solution
&lt;/h2&gt;

&lt;p&gt;While it may seem like a simple solution, writing an API to handle this scenario could prove problematic, particularly when dealing with large datasets. In such cases, the API may encounter special cases that result in failure, such as a 504 Gateway Timeout if the time limit is exceeded.&lt;/p&gt;

&lt;p&gt;Additionally, if we plan to handle huge datasets with this approach, we may need to resort to vertical scaling, which could be excessive and ultimately unsustainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the solution
&lt;/h2&gt;

&lt;p&gt;Let's start finding optimized solution for this problem, compare them objectively. So when considering for best architectures, we should consider the usual factors, i.e scalability, availability, fault tolerant, consistency and security. &lt;/p&gt;

&lt;p&gt;There are various factors that affect our solutions they are as follows,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compute resources (CPU and Memory)&lt;/li&gt;
&lt;li&gt;Database Disk IO
&lt;/li&gt;
&lt;li&gt;Network IO&lt;/li&gt;
&lt;li&gt;Data size&lt;/li&gt;
&lt;li&gt;Technical difficulties&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After a good amount of research, I was able to list down some of the best solution approaches, they are as follows,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Asynchronous approach with queues and consumers&lt;/li&gt;
&lt;li&gt;Event based approach with websockets&lt;/li&gt;
&lt;li&gt;Streaming data from API&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  1. Asynchronous approach with queues and consumers
&lt;/h3&gt;

&lt;p&gt;In this method, whenever a user clicks on the download, immediately that information is pushed to a queue. Then those requests are fulfilled by one of the consumer/worker process. The worker basically fetches the request from the queue, starts proceeding with the data fetching and data transformation. &lt;/p&gt;

&lt;p&gt;This process can take &lt;em&gt;x seconds&lt;/em&gt; which is directly proportional to the size of the data. After transformation, it will push it to S3 and then fetch the presigned URL so that it can be given to the client. Meanwhile the client would be polling backend server with an interval of &lt;em&gt;y seconds&lt;/em&gt; for this presigned URL.&lt;/p&gt;

&lt;p&gt;Here's a high level architecture view of this solution,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fejry81wk0zodv8y1jkl0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fejry81wk0zodv8y1jkl0.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; When implemented properly, this solution would provide great scalability with n workers, high availability, and failure handling with acknowledgement in queues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; The user experience would not be good. The infrastructure to setup these components might cost hefty.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Event based approach with websockets
&lt;/h3&gt;

&lt;p&gt;In this approach, instead of using conventional REST APIs, we're gonna use Websockets to make use of event driven design to eliminate the polling and the compute processing is also done at the same backend server. This can also be said to be as asynchronous, based on the design as well. &lt;/p&gt;

&lt;p&gt;The websocket is opened once the user requests for the download, the server starts to work on the data fetching, data transformation logics, computes the resultant file and pushes it to S3. After fetching the presigned URL, it is being sent the client for download. &lt;/p&gt;

&lt;p&gt;Here's an overview of the design,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fkoycen12hlmjr876zznb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fkoycen12hlmjr876zznb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; Easy to setup, cost effective.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; Infrastructure scaling for compute resource is not flexible, since processing happens in backend server.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Streaming data from API
&lt;/h3&gt;

&lt;p&gt;This approach is more straight forward, it can be achieved with the conventional API with a small change. Instead of doing the heavy lifting in a single shot and returning the response, we will be chunking and stream the response. &lt;/p&gt;

&lt;p&gt;As a user perspective, immediately after the trigger, the file starts to download. The download speed is directly proportional to the above mentioned parameters. There should be a tradeoff in terms of performance for user experience. Here's the overview of the streaming API design.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fujvmov2orq8j9ikekb5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fujvmov2orq8j9ikekb5w.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some technicalities needs to be crafted very carefully based on the infrastructure resources, such as how much records can be processed in a single chunk. A good metric is to chunk the data based on the data size. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;100 MB data can be processed in a single chunk&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;A simple implementation of streaming API with Flask - python is as follows, &lt;a href="https://flask.palletsprojects.com/en/2.1.x/patterns/streaming/" rel="noopener noreferrer"&gt;flask docs&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;/large.csv&lt;/span&gt;&lt;span class="sh"&gt;'&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;generate_large_csv&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;generate&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;iter_all_rows&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;response_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;mimetype&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text/csv&lt;/span&gt;&lt;span class="sh"&gt;'&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;Pros:&lt;/strong&gt; Easy to setup, cost effective, best user experience etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cons:&lt;/strong&gt; Infrastructure scaling for compute resource is not flexible, since processing happens in backend server.&lt;/p&gt;

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

&lt;p&gt;All the three approches offers a powerful, best in class solution, if implemented properly, but opting 1of these 3 should be based on your usecase/needs, you can use anyone of these solution to handle the large files. The third approach of streaming data was matching best for my usecase, so I went with the same. Ofcourse there can be issues at the implementation level, which are ignored in this article for the sake of simplicity.&lt;/p&gt;

&lt;p&gt;Share your perspective in the comments.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>architecture</category>
      <category>restapi</category>
      <category>flask</category>
    </item>
  </channel>
</rss>
