<?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: Iñigo Etxaniz</title>
    <description>The latest articles on DEV Community by Iñigo Etxaniz (@ietxaniz).</description>
    <link>https://dev.to/ietxaniz</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%2F1209293%2F70dbc518-08f7-48fa-bce4-d49d1ac2bb50.jpeg</url>
      <title>DEV Community: Iñigo Etxaniz</title>
      <link>https://dev.to/ietxaniz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ietxaniz"/>
    <language>en</language>
    <item>
      <title>Running Ollama in a Container Without Internet Access</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Fri, 14 Feb 2025 11:21:47 +0000</pubDate>
      <link>https://dev.to/ietxaniz/running-ollama-in-a-container-without-internet-access-1a1m</link>
      <guid>https://dev.to/ietxaniz/running-ollama-in-a-container-without-internet-access-1a1m</guid>
      <description>&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;This setup has been tested on &lt;strong&gt;Ubuntu&lt;/strong&gt;. To enable GPU acceleration, install the &lt;strong&gt;NVIDIA Container Toolkit&lt;/strong&gt; before running the project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nvidia-container-toolkit
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;p&gt;With the growing demand for AI-powered applications, running large language models locally is becoming increasingly common. However, in some cases, it is essential to ensure confidentiality and prevent unintended data leaks by &lt;strong&gt;running Ollama in a fully sandboxed environment without internet access&lt;/strong&gt;. This setup allows organizations or individuals to maintain full control over their AI models while still leveraging their capabilities.&lt;/p&gt;

&lt;p&gt;Additionally, this setup enables &lt;strong&gt;fine-grained control over networking&lt;/strong&gt;, allowing a &lt;strong&gt;dedicated model-downloading instance&lt;/strong&gt; to have internet access while keeping the &lt;strong&gt;model-serving instance&lt;/strong&gt; completely isolated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project Overview
&lt;/h2&gt;

&lt;p&gt;This project provides a &lt;strong&gt;Docker-based solution&lt;/strong&gt; to run Ollama models in an isolated environment while keeping the model-downloading instance in a normal network. The architecture consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ollama Runner&lt;/strong&gt;: Runs AI models in a sandboxed network without internet access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ollama Updater&lt;/strong&gt;: Responsible for downloading models from the internet and sharing them with the runner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nginx Reverse Proxy&lt;/strong&gt;: Bridges the network gap, allowing access to the runner while maintaining isolation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tested with VS Code's Continue Extension
&lt;/h2&gt;

&lt;p&gt;To ensure practical usability, I tested this configuration with the &lt;strong&gt;Continue extension in Visual Studio Code&lt;/strong&gt;, and it worked correctly. This means developers can integrate the local Ollama instance seamlessly with their workflow while keeping the model execution isolated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demonstrating Network Isolation
&lt;/h2&gt;

&lt;p&gt;One of the key aspects of this project is &lt;strong&gt;network isolation&lt;/strong&gt;, ensuring that the &lt;strong&gt;Ollama Runner&lt;/strong&gt; does not have internet access while the &lt;strong&gt;Ollama Updater&lt;/strong&gt; does. To verify this, we can run the following script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash network-isolation-test-script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script performs the following tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Check internet access&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ollama-updater&lt;/code&gt; container should be able to reach &lt;code&gt;google.com&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ollama-runner&lt;/code&gt; container should be &lt;strong&gt;fully isolated&lt;/strong&gt; and unable to reach the internet.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Check Ollama API accessibility&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ollama-runner&lt;/code&gt; should be able to access its API internally.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ollama-updater&lt;/code&gt; should be able to access its own API.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ ollama-updater network has internet access (Expected)
✓ ollama-runner network is properly isolated (Expected)
✓ Ollama API accessible from runner network
✓ Ollama API accessible from updater network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirms that &lt;strong&gt;the model execution environment remains secure and offline&lt;/strong&gt;, while updates can still be managed efficiently.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Fully sandboxed Ollama model execution&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate container for downloading models&lt;/strong&gt; with internet access&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nginx reverse proxy for controlled access&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom small Docker networks (&lt;code&gt;/28&lt;/code&gt;)&lt;/strong&gt; to ensure isolation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GPU acceleration via NVIDIA toolkit&lt;/strong&gt; (if available)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Deployment Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Install Docker and NVIDIA Container Toolkit (if using GPU).&lt;/li&gt;
&lt;li&gt;Clone the repository:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   git clone https://github.com/ietxaniz/ollama-local.git
   &lt;span class="nb"&gt;cd &lt;/span&gt;ollama-local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Start the services:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker-compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Verify running containers:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Use the &lt;strong&gt;Ollama Runner&lt;/strong&gt; to serve models, while the &lt;strong&gt;Ollama Updater&lt;/strong&gt; manages downloads.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Managing Models
&lt;/h3&gt;

&lt;p&gt;To list available models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; ollama-runner ollama &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To pull new models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; ollama-updater ollama pull deepseek-r1:14b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check active models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; ollama-runner ollama ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Future Possibilities
&lt;/h2&gt;

&lt;p&gt;While this project provides a robust foundation for securely running Ollama, I am considering extending it further to explore &lt;strong&gt;Retrieval-Augmented Generation (RAG)&lt;/strong&gt;. This could enhance local AI capabilities by integrating external knowledge bases while keeping execution sandboxed.&lt;/p&gt;

&lt;p&gt;If you're interested in contributing or have suggestions, feel free to open an issue in the &lt;a href="https://github.com/ietxaniz/ollama-local" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;This setup ensures that &lt;strong&gt;AI models can run securely in an isolated environment&lt;/strong&gt; while maintaining the flexibility to update and manage them efficiently. Whether for security reasons or simply to experiment with self-hosted AI, this approach provides a reliable solution.&lt;/p&gt;

&lt;p&gt;Would you like to see more extensions of this project? Let me know in the comments!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>ai</category>
      <category>selfhosted</category>
      <category>security</category>
    </item>
    <item>
      <title>Enhancing Rust Error Handling: Macro to add Program Flow Trace to your applications</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Sun, 21 Jul 2024 09:01:28 +0000</pubDate>
      <link>https://dev.to/ietxaniz/enhancing-rust-error-handling-macro-to-add-program-flow-trace-to-your-applications-409</link>
      <guid>https://dev.to/ietxaniz/enhancing-rust-error-handling-macro-to-add-program-flow-trace-to-your-applications-409</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When developing Rust applications, error handling is a crucial aspect that can significantly impact the debugging process and overall maintainability of your code. While Rust's error messages are generally informative about why an error occurred, they often fall short in providing insight into the program's flow leading up to that error. In complex applications with multiple layers of function calls, understanding the sequence of events that led to an error can be challenging.&lt;/p&gt;

&lt;p&gt;To address this challenge, I have developed an approach that enhances Rust's error handling capabilities by incorporating program flow information directly into error messages. This method combines custom traits, macros, and the &lt;code&gt;anyhow&lt;/code&gt; crate to provide a more comprehensive error reporting system.&lt;/p&gt;

&lt;p&gt;Here's a snippet that demonstrates how clean and straightforward the implementation can be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;debug_err!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parse_argument&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Error parsing command-line argument"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;debug_err!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;intermediate_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Success: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this approach allows you to add debug information to your error handling with minimal impact on your code's readability. The &lt;code&gt;debug_err!&lt;/code&gt; macro seamlessly integrates with Rust's &lt;code&gt;?&lt;/code&gt; operator, maintaining the concise style that Rust developers appreciate. It also provides flexibility by allowing optional custom error messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;debug_err!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;some_operation&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Adds file and line information&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;debug_err!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;some_operation&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Custom error message"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Adds custom message along with file and line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's look at how this solution works in practice with a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Successful execution:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $ cargo run -- 12
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
    Running `target/debug/rust_error_handling 12`
    Success: you guessed correctly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Error in main operation:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   $ cargo run -- 89
   Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
   Running `target/debug/rust_error_handling 89`
   Error: 
   (at src/some_module/mod.rs:28): Error in intermediate_function
   (at src/some_module/mod.rs:23): Invalid input: 89
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Error in parsing command-line argument:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   $ cargo run -- io
   Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
   Running `target/debug/rust_error_handling io`
   Error: Error parsing command-line argument
   (at src/some_module/mod.rs:27): Failed to parse input as integer: invalid digit found in string
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, in cases where an error occurs, our enhanced error messages provide the reason for the error along with the file and line number, offering a clear picture of how the program reached the error state. The custom messages, when provided, offer additional context to aid in debugging.&lt;/p&gt;

&lt;p&gt;In the following sections, we'll dive into the implementation details of this error handling approach, explore its benefits and potential drawbacks, and discuss best practices for incorporating it into your Rust projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation and Example
&lt;/h2&gt;

&lt;p&gt;Let's walk through the implementation of our enhanced error handling approach and demonstrate its usage with a practical example. We'll start by creating a new Rust project and then build our error handling system step by step.&lt;/p&gt;

&lt;p&gt;Begin by creating a new Rust project and adding the necessary dependency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo new rust_error_handling_example
&lt;span class="nb"&gt;cd &lt;/span&gt;rust_error_handling_example
cargo add anyhow
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create a new project and add &lt;code&gt;anyhow&lt;/code&gt; to your &lt;code&gt;Cargo.toml&lt;/code&gt; file. Now, let's set up our project structure. Create the following directories and files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/
|-- error_handling/
|   |-- mod.rs
|-- some_module/
|   |-- mod.rs
|-- main.rs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that our project is set up, let's implement our core error handling logic. Create &lt;code&gt;src/error_handling/mod.rs&lt;/code&gt; and add the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&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="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;AddDebugInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;add_debug_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&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="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;AddDebugInfo&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;add_debug_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&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="nb"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.with_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;(at {}:{})"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;(at {}:{})"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[macro_export]&lt;/span&gt;
&lt;span class="nd"&gt;macro_rules!&lt;/span&gt; &lt;span class="n"&gt;debug_err&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result:expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="nf"&gt;.add_debug_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;file!&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nd"&gt;line!&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result:expr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$msg:expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="nf"&gt;.add_debug_info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$msg&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="nd"&gt;file!&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nd"&gt;line!&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code defines the &lt;code&gt;AddDebugInfo&lt;/code&gt; trait and implements it for &lt;code&gt;Result&amp;lt;T&amp;gt;&lt;/code&gt;. The &lt;code&gt;debug_err!&lt;/code&gt; macro provides a convenient way to add debug information to errors, with or without custom messages.&lt;/p&gt;

&lt;p&gt;Next, let's create a module that demonstrates our error handling approach. Create &lt;code&gt;src/some_module/mod.rs&lt;/code&gt;, with following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&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="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error_handling&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;AddDebugInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;debug_err&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;parse_argument&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.collect&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;args&lt;/span&gt;&lt;span class="nf"&gt;.len&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&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;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;anyhow!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Expected exactly one argument"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="py"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to parse input as integer"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;some_fallible_operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"you guessed correctly"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;anyhow!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid input: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;intermediate_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;debug_err!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;some_fallible_operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"Error in intermediate_function"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;debug_err!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;parse_argument&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="s"&gt;"Error parsing command-line argument"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;debug_err!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;intermediate_function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Success: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This module demonstrates various ways to use our error handling pattern. In &lt;code&gt;parse_argument()&lt;/code&gt;, we use the standard &lt;code&gt;context()&lt;/code&gt; method from &lt;code&gt;anyhow&lt;/code&gt; to add a simple error message. In &lt;code&gt;intermediate_function()&lt;/code&gt;, we use &lt;code&gt;debug_err!&lt;/code&gt; with a custom message. The &lt;code&gt;run()&lt;/code&gt; function shows how to chain multiple operations using &lt;code&gt;debug_err!&lt;/code&gt;, adding contextual information at each step.&lt;/p&gt;

&lt;p&gt;Finally, update &lt;code&gt;src/main.rs&lt;/code&gt; to use our new module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;error_handling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;some_module&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Err&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="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;some_module&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error: {:#}"&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="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;process&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can run the example with different inputs to see how the error handling works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo run &lt;span class="nt"&gt;--&lt;/span&gt; 12
cargo run &lt;span class="nt"&gt;--&lt;/span&gt; 89
cargo run &lt;span class="nt"&gt;--&lt;/span&gt; io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When an error occurs, it will be displayed with the added context and location information, making it easier to trace and debug issues in your Rust applications. This pattern allows you to add contextual information at each step, creating a trail of debug information that helps trace the error's origin and path through the program.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflections on the Approach
&lt;/h2&gt;

&lt;p&gt;Coming from a Go background, I often find myself struggling with error handling in Rust. Despite Rust's powerful type system and the &lt;code&gt;Result&lt;/code&gt; type, I frequently encounter situations where tracing the origin and path of errors through my codebase is more challenging than it should be. This struggle has led me to explore alternative approaches, ultimately resulting in the error handling pattern presented in this article.&lt;/p&gt;

&lt;p&gt;The primary motivation behind developing this approach is to enhance the debugging process in my Rust applications. I want a method that can provide detailed context about where and how errors occur, significantly reducing the time and effort required to trace and resolve issues. After implementing this pattern, I have decided to change how I manage errors in my future Rust projects and potentially refactor existing codebases to incorporate this new approach.&lt;/p&gt;

&lt;p&gt;One of the most compelling aspects of this method is the automatic inclusion of file and line information in error messages. I anticipate this feature will be particularly valuable when dealing with complex codebases, as it should immediately pinpoint the exact location where an error originates or is propagated. The flexibility to add optional custom messages also allows for the inclusion of rich, contextual information about the program's state at the time of the error.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;debug_err!&lt;/code&gt; macro is a key component of this new approach. I have designed it to integrate seamlessly with Rust's &lt;code&gt;?&lt;/code&gt; operator, allowing for concise error propagation while still maintaining detailed error context. My hope is that this will lead to more readable and maintainable code, as error handling becomes less intrusive and more informative.&lt;/p&gt;

&lt;p&gt;However, I'm aware that this approach isn't without potential drawbacks. There might be a slight performance overhead associated with capturing and storing additional context information. While I expect this overhead to be negligible in most applications, it could become a consideration in performance-critical sections of code or in systems with extremely high throughput.&lt;/p&gt;

&lt;p&gt;As I move forward with adopting this pattern, I plan to use it judiciously and in balance with other error handling techniques. For instance, I intend to use &lt;code&gt;debug_err!&lt;/code&gt; with custom messages at significant points in the program flow or when crossing module boundaries. For simpler, more localized error cases, I might stick with &lt;code&gt;anyhow&lt;/code&gt;'s standard &lt;code&gt;context&lt;/code&gt; method or even Rust's built-in &lt;code&gt;?&lt;/code&gt; operator without additional context.&lt;/p&gt;

&lt;p&gt;When it comes to balancing detail and performance, I'm considering a strategy of using more detailed error messages in development and testing environments, while potentially scaling back the verbosity in production builds if performance becomes a concern. This could be achieved through conditional compilation or runtime flags.&lt;/p&gt;

&lt;p&gt;Integrating this approach with existing error handling patterns in my projects will require careful consideration. In codebases that already have established error types or handling mechanisms, I plan to gradually introduce this method, starting with areas that would benefit most from enhanced debugging information.&lt;/p&gt;

&lt;p&gt;While I haven't extensively used this error handling approach in production yet, I'm optimistic about its potential to improve my Rust development experience. I look forward to seeing how it performs in real-world scenarios and how it might evolve based on practical usage. As with any new technique, I expect there will be a learning curve and possibly some adjustments needed along the way. However, I believe the potential benefits in terms of improved debugging capabilities and code maintainability make it worth exploring and implementing in my future Rust projects.&lt;/p&gt;

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

&lt;p&gt;The enhanced error handling approach I've presented in this article offers a solution to a challenge I've often encountered in Rust development. By incorporating program flow information directly into error messages, I believe I can significantly improve my debugging process and the overall maintainability of my Rust applications. This method provides detailed context by automatically including file and line information in error messages, while offering the flexibility of optional custom messages for rich, contextual information. I've designed it to integrate seamlessly with Rust's &lt;code&gt;?&lt;/code&gt; operator and existing error handling patterns, ensuring that I can adopt this approach without disrupting my current coding practices. I anticipate this will result in a substantial reduction in the time and effort required to trace and resolve issues, especially in the complex codebases I work with. While I'm aware of potential minor performance considerations in certain scenarios, I believe the improvements in code readability, maintainability, and debugging efficiency will make this approach a valuable addition to my Rust developer toolkit. As I prepare to implement and refine this error handling pattern in my real-world projects, I look forward to gaining practical insights and making further optimizations. My goal is to make my Rust development more efficient and enjoyable, allowing me to focus on solving problems rather than tracking down elusive errors. By sharing this approach, I hope other Rust developers might find it useful and potentially benefit from it in their own work as well.&lt;/p&gt;

&lt;p&gt;I am not an expert in Rust, but I've adapted principles I found useful in Go to the Rust ecosystem. I hope this method proves helpful to others facing similar challenges in debugging and maintaining Rust applications. If you have more experience in Rust or suggestions for improving this approach, I would greatly appreciate your feedback. Let's continue to evolve and refine our error handling techniques together.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>errors</category>
      <category>debugging</category>
      <category>programming</category>
    </item>
    <item>
      <title>Introducing CurlDock: Simplify API Testing with Docker and Curl</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Mon, 08 Jul 2024 18:26:33 +0000</pubDate>
      <link>https://dev.to/ietxaniz/introducing-curldock-simplify-api-testing-with-docker-and-curl-5ajo</link>
      <guid>https://dev.to/ietxaniz/introducing-curldock-simplify-api-testing-with-docker-and-curl-5ajo</guid>
      <description>&lt;p&gt;Hey Dev.to community!&lt;/p&gt;

&lt;p&gt;I'm excited to share CurlDock, a lightweight open-source tool I've been working on to simplify API testing and curl script management.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CurlDock?
&lt;/h2&gt;

&lt;p&gt;CurlDock combines the power of curl with the convenience of Docker, offering a user-friendly interface for creating, editing, and executing curl commands. Built with Rust and React, it's designed for simplicity and ease of use.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🐳 &lt;strong&gt;Dockerized&lt;/strong&gt;: Easy setup and consistent environments&lt;/li&gt;
&lt;li&gt;🖥️ &lt;strong&gt;User-Friendly Interface&lt;/strong&gt;: Similar to Postman or Insomnia&lt;/li&gt;
&lt;li&gt;📁 &lt;strong&gt;Git-Friendly&lt;/strong&gt;: Store scripts as .sh files for easy version control&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Network Isolation&lt;/strong&gt;: Access endpoints within your Docker network&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Start
&lt;/h2&gt;

&lt;p&gt;Getting started with CurlDock is as easy as running a Docker command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; curldock &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;SCRIPTSFOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/scripts"&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/scripts:/scripts &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"2080"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 2080:2080 inigoetxaniz/curldock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, just open &lt;code&gt;http://localhost:2080&lt;/code&gt; in your browser!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CurlDock?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Simplicity&lt;/strong&gt;: Focus on core functionality without unnecessary complexity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local-First&lt;/strong&gt;: Designed for local development environments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Authentication&lt;/strong&gt;: Reduced complexity for improved usability&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer Control&lt;/strong&gt;: You manage your own security measures&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Try It Out!
&lt;/h2&gt;

&lt;p&gt;I'd love for you to give CurlDock a spin and share your thoughts. &lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/ietxaniz/curldock" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; for more details!&lt;/p&gt;

&lt;p&gt;Happy API testing! 🚀&lt;/p&gt;

</description>
      <category>curl</category>
      <category>api</category>
      <category>docker</category>
      <category>devtools</category>
    </item>
    <item>
      <title>Deferred Redux Update Pattern</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Sun, 07 Jul 2024 07:43:12 +0000</pubDate>
      <link>https://dev.to/ietxaniz/deferred-redux-update-pattern-1d33</link>
      <guid>https://dev.to/ietxaniz/deferred-redux-update-pattern-1d33</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When developing user interfaces with React, I often find myself juggling between different state management approaches. On one hand, Redux is great for handling large-scale application state, but on the other, useState is perfect for those small, component-specific details.&lt;/p&gt;

&lt;p&gt;During a recent project, I was looking for a way to have the best of both worlds - using Redux for the big picture stuff while keeping the nitty-gritty details managed by useState. It wasn't straightforward, and I had to experiment quite a bit before I stumbled upon a pattern that seemed to work well.&lt;/p&gt;

&lt;p&gt;After a few iterations and some refinement, I realized I had something that could be useful in future projects.  This pattern basically allows components to work with complex state locally, making as many changes as needed, without bombarding Redux with updates for every little change. Instead, it waits until the right moment - like when a form is submitted or a component is about to unmount - before pushing all those changes to the global Redux store.&lt;/p&gt;

&lt;p&gt;I thought this approach might be helpful for other developers facing similar challenges, so I decided to share it here. In this article, I'll walk you through the problem this pattern solves and how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The main Use Case
&lt;/h2&gt;

&lt;p&gt;The Deferred Redux Update Pattern is useful in scenarios where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Your Redux store maintains complex state structures.&lt;/li&gt;
&lt;li&gt;Components need to make frequent, granular updates to this state.&lt;/li&gt;
&lt;li&gt;These updates don't need to be immediately reflected in the global store.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Consider a form with multiple fields, each represented in Redux. Traditional approaches might dispatch an action for every keystroke, leading to unnecessary re-renders and potential performance issues. With the Deferred Redux Update Pattern, we can buffer these changes locally and only update Redux when the form is submitted or the component unmounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rel-World Example: curldock
&lt;/h2&gt;

&lt;p&gt;To better illustrate the Deferred Redux Update Pattern, let's explore how it's implemented in &lt;a href="https://github.com/ietxaniz/curldock" rel="noopener noreferrer"&gt;curldock&lt;/a&gt;, an open-source project I am working on. curldock is designed to simplify API testing, allowing developers to have an user interface for interacting with curl.&lt;/p&gt;

&lt;p&gt;Curldock's user interface (although not finished) consists of three main components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A FileExplorer component that allows interacting with a hierarchical list of curl scripts.&lt;/li&gt;
&lt;li&gt;A ScriptEditor component that allows users to edit and send API requests.&lt;/li&gt;
&lt;li&gt;A ResultViewer component that will allow reviewing the response from the api call.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a simplified view of the application layout:&lt;/p&gt;

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

&lt;p&gt;The application's data flow and state management can be visualized as follows:&lt;/p&gt;

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

&lt;p&gt;In curldock, the Deferred Redux Update Pattern is primarily used in the ScriptEditor component. Here's how it's implemented:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useGetCurlItemByFileId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useUpdateCurlItem&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/store/hooks/useCurl&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HttpMethod&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@/store/slices/curlSlice&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useScriptEditorData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;initialized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setInitialized&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getCurlItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useGetCurlItemByFileId&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updateCurlItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useUpdateCurlItem&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMethod&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;HttpMethod&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;HttpMethod&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUrl&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHeaders&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bodyContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBodyContent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exitCallbackRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

  &lt;span class="nx"&gt;exitCallbackRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`close &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fileId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;updateCurlItem&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;fileId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
          &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bodyContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;insecure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;curlItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getCurlItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curlItem&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;curlItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curlItem&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;curlItem&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;setMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})));&lt;/span&gt;
      &lt;span class="nf"&gt;setBodyContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nf"&gt;setInitialized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`open &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;fileId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exitCallbackRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;fileId&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="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMethod&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setHeaders&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bodyContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setBodyContent&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implementation allows the ScriptEditor to work with complex state locally, making as many changes as needed without immediately updating Redux. The state is only synchronized with Redux when the component unmounts or when explicitly triggered by the user (e.g., saving the script).&lt;/p&gt;

&lt;p&gt;By using this pattern, curldock achieves several benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Better performance and a more responsive user interface, especially when dealing with complex forms and real-time data manipulation in the ScriptEditor.&lt;/li&gt;
&lt;li&gt;Cleaner code, as detailed Redux updating function calls are not needed throughout the component logic.&lt;/li&gt;
&lt;li&gt;Improved state management, with clear separation between local state and global (Redux) state.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Problem in Detail
&lt;/h2&gt;

&lt;p&gt;As I dug deeper into implementing this pattern, I ran into a few roadblocks that really made me scratch my head. The main issue I was grappling with was how to trigger the Redux update only when the component disappears, without causing unnecessary updates or running into stale data problems. At first, I thought I could manage everything with useEffect. Seems straightforward, right? But I quickly realized that if all the internal states were managed by useEffect, the cleanup function would fire every time an internal state changed. That wasn't what I wanted at all - it defeated the whole purpose of deferring updates! So, I tried using useCallback, thinking it might solve the problem. But, I ran into similar issues. It was like trying to plug a leak only to find another one popping up elsewhere. For a moment, I considered using useRef to store the state. But then I realized I'd essentially be keeping two copies of the state around. It felt like overkill, and I worried it might lead to synchronization headaches down the line. But, what if I used useRef, not for the state itself, but to manage a closing function? This approach turned out to be the key to solving my update timing problem.&lt;/p&gt;

&lt;p&gt;But just when I thought I had it all figured out, React's Strict Mode threw me another curveball. In Strict Mode, useEffect gets called twice in each render. At first, this seemed like a minor inconvenience, but it quickly turned into a real problem. You see, the first cleanup call happens before the states are updated from Redux. If I didn't account for this, I risked storing empty data in Redux. Not exactly the behavior I was aiming for! After some more tinkering, I found a solution: a simple state that checks if all other states have been updated. It's a small addition, but it made all the difference in handling Strict Mode's double-call behavior.&lt;/p&gt;

&lt;p&gt;These challenges really drove home the need for a more robust way to manage state updates in React-Redux applications. The solution I eventually landed on might not be perfect, but it addressed these pain points and gave me a pattern I could rely on. Let me show you how it all came together.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Deferred Redux Update Pattern
&lt;/h2&gt;

&lt;p&gt;The Deferred Redux Update Pattern addresses these challenges by introducing a mechanism to delay Redux updates until they're necessary. Here's an overview of the key components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Local State Management&lt;/strong&gt;: Use React's useState for managing state within the component.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cleanup Function with useRef&lt;/strong&gt;: Store the cleanup function in a useRef to ensure it always has access to the most recent state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Initialization Flag&lt;/strong&gt;: Implement an isInitialized flag to handle React Strict Mode's double-invocation behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deferred Redux Update&lt;/strong&gt;: Trigger the Redux update in the cleanup function, which runs when the component unmounts or when explicitly called.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's a code example demonstrating the pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useDispatch&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;react-redux&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useDeferredReduxUpdate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initialState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isInitialized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsInitialized&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dispatch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useDispatch&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cleanupRef&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useRef&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{});&lt;/span&gt;

  &lt;span class="nx"&gt;cleanupRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isInitialized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;dispatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;updateAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&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;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setIsInitialized&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;cleanupRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;storeCurrentState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cleanupRef&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;storeCurrentState&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, the hook exposes a storeCurrentState function, providing flexibility to trigger a Redux update on demand. This function can be called to push the local state to Redux at any time, such as when a user activates a "Save" button.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits and Use Cases
&lt;/h2&gt;

&lt;p&gt;The Deferred Redux Update Pattern offers several key benefits:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Improved Performance&lt;/strong&gt;: By reducing the number of Redux dispatches, we minimize unnecessary re-renders and state calculations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cleaner Code&lt;/strong&gt;: The pattern encapsulates the logic for managing local state and syncing with Redux, leading to more maintainable components.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Better User Experience&lt;/strong&gt;: With fewer global state updates, the application can feel more responsive, especially when dealing with form inputs or real-time data manipulation.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This pattern is particularly useful in scenarios such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex forms with multiple fields&lt;/li&gt;
&lt;li&gt;Data visualization tools with frequent updates&lt;/li&gt;
&lt;li&gt;Real-time collaborative features where immediate global updates aren't necessary&lt;/li&gt;
&lt;li&gt;Any situation where you need to balance local interactivity with global state consistency&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By implementing the Deferred Redux Update Pattern, you can significantly optimize your React-Redux applications, especially those dealing with complex state management scenarios.&lt;/p&gt;

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

&lt;p&gt;The Deferred Redux Update Pattern offers a powerful solution for managing complex state in React applications. By intelligently balancing local state management with global Redux updates, this pattern enhances performance, improves code clarity, and provides a smoother user experience. Whether you're working on complex forms, real-time data visualization, or collaborative features, this pattern can help enhance your state management approach. As we've seen with the curldock example, implementing this pattern can lead to more efficient and maintainable React-Redux applications. I encourage you to experiment with this pattern in your own projects and see how it can optimize your state management strategy.&lt;/p&gt;

</description>
      <category>react</category>
      <category>redux</category>
    </item>
    <item>
      <title>How to implement HTTPS in Local Networks Using Let's Encrypt</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Mon, 25 Mar 2024 10:58:10 +0000</pubDate>
      <link>https://dev.to/ietxaniz/how-to-implement-https-in-local-networks-using-lets-encrypt-4eh</link>
      <guid>https://dev.to/ietxaniz/how-to-implement-https-in-local-networks-using-lets-encrypt-4eh</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;While browsing the internet, you may have noticed that URLs sometimes begin with "HTTPS" instead of "HTTP." This extra "S" signifies a secure connection, where your communication with the website is encrypted. This encryption ensures that only you and the website can decipher the exchanged information, protecting against "Man in the Middle" (MitM) attacks. Such attacks involve interceptors eavesdropping or altering messages without detection. HTTPS scrambles the data into an indecipherable format for anyone intercepting it.&lt;/p&gt;

&lt;p&gt;The foundation of HTTPS is the certificate authority (CA) system. CAs act as trusted validators on the internet, verifying website identities and issuing digital certificates, much like ID cards for websites. This system hinges on global recognition and trust in CAs. When a website presents a certificate signed by a known CA, your browser accepts it as a signal that the website is secure.&lt;/p&gt;

&lt;p&gt;Yet, when it comes to securing local networks—such as those in your home or office—using global CAs presents challenges. These authorities cannot directly verify ownership of servers within private networks, which is crucial for issuing trusted certificates. Setting up a Private CA is an alternative, but it introduces complexities, such as the need for manual trust setup on new devices and maintaining security against vulnerabilities.&lt;/p&gt;

&lt;p&gt;Furthermore, the threat of MitM attacks isn't limited to the vast internet; it's arguably more prevalent within local networks. Shared networks, like those in offices or public Wi-Fi spots, are fertile ground for malicious users to intercept unencrypted traffic. This risk underscores the necessity of HTTPS, ensuring communications are confidential and integrity is maintained, even in internal networks.&lt;/p&gt;

&lt;p&gt;The approach we're about to explore, inspired by Joshua's method in &lt;a href="https://dev.to/joshwizzy/how-to-secure-a-web-application-running-on-a-private-network-el2"&gt;securing web applications on private networks&lt;/a&gt;, involves using Certbot and Let's Encrypt for a streamlined solution. This method sidesteps direct server connection requirements by using DNS verification, making it suitable for internal networks. We begin by securing a domain name, setting up Certbot within Docker for certificate issuance, and finally configuring an Nginx web server to utilize the SSL/TLS certificate. This process, detailed further in the article, not only secures our network but does so in a cost-effective and accessible manner.&lt;/p&gt;

&lt;p&gt;To facilitate the implementation of the HTTPS setup described in this article, I've prepared a comprehensive repository containing all the scripts. You can find everything you need to get started at &lt;a href="https://github.com/ietxaniz/https-setup-local-networks"&gt;https://github.com/ietxaniz/https-setup-local-networks&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding HTTPS and Its Importance
&lt;/h2&gt;

&lt;p&gt;HTTPS is crucial for internet security, transforming HTTP into a secure channel using SSL/TLS protocols. These protocols encrypt data in transit, ensuring confidentiality and integrity. The process relies on asymmetric encryption, using a public key for encryption and a private key for decryption. Even if data is intercepted, it remains unreadable without the private key.&lt;/p&gt;

&lt;p&gt;Security extends beyond encryption. An SSL/TLS certificate acts as proof that you're communicating with the intended server. Issued by trusted Certificate Authorities (CAs) after rigorous verification, it’s akin to verifying the authenticity of an ID card before granting access. This protects users from potential frauds and attacks.&lt;/p&gt;

&lt;p&gt;At the beginning of each secure session, a handshake process lays the groundwork for a secure connection. This process includes server authentication, key exchange, and secure communication using symmetric encryption. The handshake ensures that the communication channel is private, authenticated, and untampered with, marking the transition from the computational rigor of asymmetric encryption to the efficiency of symmetric encryption.&lt;/p&gt;

&lt;p&gt;HTTPS signifies trustworthiness, indicated by the padlock icon in the browser's address bar. This trust is crucial for websites handling sensitive information, as it assures users that their data is safe. Periodic renewal of SSL/TLS certificates acts as a continual check, ensuring encryption standards evolve to meet new security challenges and technological advances.&lt;/p&gt;

&lt;p&gt;In the broader digital landscape, HTTPS is not just a technical specification; it is a foundational element of online security, privacy, and trust. Its role in safeguarding data integrity, authenticating website identities, and ensuring confidentiality is paramount. Understanding these principles is essential for implementing robust security measures that protect against digital vulnerabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Role of Certificate Authorities (CAs)
&lt;/h2&gt;

&lt;p&gt;Certificate Authorities (CAs) are crucial to the HTTPS ecosystem, ensuring secure and trustworthy communications between browsers and websites. These trusted entities issue digital certificates, essential for establishing encrypted connections in the SSL/TLS protocol.&lt;/p&gt;

&lt;p&gt;Digital certificates serve as electronic "passports" for websites, proving their identity to visitors. When you access a secure website, your browser checks the site's digital certificate, verifying it was issued by a CA that the browser trusts. This verification process prevents attackers from masquerading as legitimate websites, a common tactic in phishing attacks.&lt;/p&gt;

&lt;p&gt;Understanding the distinction between global CAs and private CAs is essential. Global CAs, such as Let's Encrypt, VeriSign, and Comodo, are widely recognized and trusted, issuing certificates automatically trusted by most web browsers and operating systems. However, their use in local networks can present challenges, as they cannot directly validate servers within private networks.&lt;/p&gt;

&lt;p&gt;Private CAs, in contrast, are internal to an organization and not automatically trusted by external systems. They issue certificates for internal servers and applications, where external validation is not feasible or necessary. While private CAs offer flexibility in securing internal communications, they require manual trust management and secure handling of the CA’s private key to prevent unauthorized certificate issuance.&lt;/p&gt;

&lt;p&gt;In conclusion, using global Certificate Authorities for private networks simplifies the certification process and enhances security without compromising trustworthiness or administrative overhead. This approach combines the reliability of global CAs with the control of internal network management, eliminating the disadvantages traditionally associated with private CAs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's Encrypt and Certbot
&lt;/h2&gt;

&lt;p&gt;Let's Encrypt offers an automated, open service for obtaining digital certificates, simplifying web security. Founded on the principle of accessible privacy and security, it streamlines the process of certificate renewal. This initiative benefits both small and large organizations by securing local networks without significant costs or administrative burdens.&lt;/p&gt;

&lt;p&gt;Certbot, a free, open-source software tool, automates obtaining, installing, and renewing certificates from Let's Encrypt. Designed to work with various web servers and operating systems, Certbot ensures that secure HTTPS is attainable regardless of the technical environment.&lt;/p&gt;

&lt;p&gt;In this tutorial, we use the Docker version of Certbot, leveraging Docker's ability to simplify infrastructure management. Using Docker, we avoid complex installations, utilizing containers for a clean and easily replicable setup. We extend the base Certbot image to include &lt;code&gt;curl&lt;/code&gt;, enabling more sophisticated scripts and interactions during the certificate setup process.&lt;/p&gt;

&lt;p&gt;First, create a Dockerfile instructing Docker on how to build our customized Certbot image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; certbot/certbot:latest&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--update&lt;/span&gt; &lt;span class="nt"&gt;--no-cache&lt;/span&gt; jq curl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Accompany this Dockerfile with a build script, &lt;code&gt;build.sh&lt;/code&gt;, automating the image creation process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash
docker build -t certbot-with-curl .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save these files in a dedicated directory. Ensure you grant execution permissions to the build script by running &lt;code&gt;chmod +x build.sh&lt;/code&gt; in your terminal. Execute the build script by navigating to the directory containing &lt;code&gt;build.sh&lt;/code&gt; and running &lt;code&gt;./build.sh&lt;/code&gt;. This command builds a new Docker image named &lt;code&gt;certbot-with-curl&lt;/code&gt;, including all necessary tools for certificate management tasks.&lt;/p&gt;

&lt;p&gt;With these preparations complete, we proceed to the certificate generation process, ensuring a versatile and robust environment for HTTPS configuration tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  DNS Management
&lt;/h2&gt;

&lt;p&gt;Securing your web application with HTTPS requires proving ownership of your domain, making DNS management essential. This step is particularly critical in environments with dynamic IP addresses or private networks. While various DNS providers are available, this guide focuses on using DuckDNS, a user-friendly, cost-effective option for linking your domain name to your server's IP address.&lt;/p&gt;

&lt;p&gt;First, create an account on DuckDNS, which supports OAuth for quick sign-up using existing social media accounts. After creating your account, set up your domain. For this guide, "inner-private" is the example domain name. Follow these steps to configure your domain:&lt;/p&gt;

&lt;p&gt;Log into DuckDNS and navigate to the domain management page. Enter your chosen domain name in the designated field and add the domain. Manually change the automatically detected public IP address to your specific private IP address. Save the changes.&lt;/p&gt;

&lt;p&gt;To verify domain ownership, Let's Encrypt performs a DNS challenge, requiring a specific TXT record in your domain's DNS settings. The &lt;code&gt;add_duckdns_txt_record.sh&lt;/code&gt; script automates updating your domain's TXT record via DuckDNS's API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="nv"&gt;DUCKDNS_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"YOUR_TOKEN"&lt;/span&gt;
&lt;span class="nv"&gt;DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"inner-private"&lt;/span&gt;
&lt;span class="nv"&gt;VALIDATION_STRING&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$CERTBOT_VALIDATION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
curl &lt;span class="s2"&gt;"https://www.duckdns.org/update?domains=_acme-challenge.&lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;token=&lt;/span&gt;&lt;span class="nv"&gt;$DUCKDNS_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;txt=&lt;/span&gt;&lt;span class="nv"&gt;$VALIDATION_STRING&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;90
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prepare and test the script by replacing &lt;code&gt;"YOUR_TOKEN"&lt;/code&gt; with your actual DuckDNS token, making it executable, and verifying the TXT record update. This setup simplifies securing your web application with HTTPS by automating the DNS challenge process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating and Storing the Certificates
&lt;/h2&gt;

&lt;p&gt;Storing SSL/TLS certificates in Docker volumes offers a convenient and secure way to manage these sensitive files. For this setup, use two Docker volumes: &lt;code&gt;https_keys&lt;/code&gt; for storing keys and &lt;code&gt;https_challenge&lt;/code&gt; for temporary files used by Certbot. Follow these steps to generate and renew your certificates:&lt;/p&gt;

&lt;p&gt;Create the necessary Docker volumes using the &lt;code&gt;create_volumes.sh&lt;/code&gt; script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
docker volume &lt;span class="nb"&gt;rm &lt;/span&gt;https_keys https_challenge
docker volume create https_keys
docker volume create https_challenge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Generate a certificate using a customized Certbot Docker container. The &lt;code&gt;create_certificates.sh&lt;/code&gt; script initiates the certificate generation process, including hooks for DNS challenges required for domain verification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"inner-private.duckdns.org"&lt;/span&gt;
docker run &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; https_keys:/etc/letsencrypt &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; https_challenge:/var/lib/letsencrypt &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/scripts:/scripts"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--env&lt;/span&gt; &lt;span class="nv"&gt;CERTBOT_DOMAIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    certbot-with-curl &lt;span class="se"&gt;\&lt;/span&gt;
    certonly &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--staging&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--verbose&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--manual&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--preferred-challenges&lt;/span&gt; dns &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--manual-auth-hook&lt;/span&gt; &lt;span class="s2"&gt;"/scripts/add_duckdns_txt_record.sh &lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--manual-cleanup-hook&lt;/span&gt; &lt;span class="s2"&gt;"/scripts/remove_duckdns_txt_record.sh &lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$DOMAIN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--non-interactive&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--agree-tos&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--email&lt;/span&gt; me@inner-private.duckdns.org
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After verifying your setup in the staging environment, remove the &lt;code&gt;--staging&lt;/code&gt; flag from the script and re-run it to obtain a production certificate. Certificates from Let's Encrypt are valid for 90 days, so set up a cron job to automate renewal by periodically re-executing this script.&lt;/p&gt;

&lt;p&gt;This approach to certificate management with Docker and Certbot simplifies securing applications. By automating certificate issuance and renewal, you ensure continuous protection for your domains with minimal overhead. Always test changes in the staging environment before applying them to production to avoid disruptions and ensure a smooth deployment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing with Nginx
&lt;/h2&gt;

&lt;p&gt;After setting up HTTPS using Certbot and Let’s Encrypt, deploy a web server to serve your content securely over HTTPS. This section provides an example of hosting a simple web server within an internal network using an Nginx container and a Let's Encrypt signed certificate. &lt;/p&gt;

&lt;p&gt;First, create a directory named after your domain (e.g., &lt;code&gt;inner-private.duckdns.org&lt;/code&gt;) and inside it, create an &lt;code&gt;index.html&lt;/code&gt; file with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Internal&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Internal web service with HTTPS.&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, configure Nginx to serve your website securely and redirect HTTP traffic to HTTPS. Create an Nginx configuration file named &lt;code&gt;inner-private.duckdns.org.conf&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;inner-private.duckdns.org&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;301&lt;/span&gt; &lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$host$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;443&lt;/span&gt; &lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;inner-private.duckdns.org&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kn"&gt;ssl_certificate&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/inner-private.duckdns.org/fullchain.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt; &lt;span class="n"&gt;/etc/letsencrypt/live/inner-private.duckdns.org/privkey.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/var/www/inner-private.duckdns.org&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt; &lt;span class="s"&gt;index.htm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kn"&gt;ssl_protocols&lt;/span&gt; &lt;span class="s"&gt;TLSv1.2&lt;/span&gt; &lt;span class="s"&gt;TLSv1.3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;ssl_ciphers&lt;/span&gt; &lt;span class="s"&gt;"ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;ssl_session_cache&lt;/span&gt; &lt;span class="s"&gt;shared:SSL:1m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kn"&gt;ssl_session_timeout&lt;/span&gt; &lt;span class="mi"&gt;10m&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, use Docker to run Nginx and serve your site. The script below sets up and starts the Nginx server in a container, mounting the necessary volumes for the SSL certificates, website content, and Nginx configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
docker run &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; rev-proxy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 80:80 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 443:443 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; https_keys:/etc/letsencrypt &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; https_challenge:/var/lib/letsencrypt &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/nginx:/etc/nginx/conf.d &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/inner-private.duckdns.org:/var/www/inner-private.duckdns.org &lt;span class="se"&gt;\&lt;/span&gt;
  nginx:1.25.1-alpine3.17-slim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script starts an Nginx container with the necessary configurations, making your site accessible over HTTPS.&lt;/p&gt;

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

&lt;p&gt;This article demonstrates how to combine Certbot, Let's Encrypt, and Docker with an Nginx setup to secure web applications on private networks. By highlighting the importance of HTTPS and providing a step-by-step guide, it equips readers to enhance network security. Leveraging automation and trusted global CAs, this approach makes advanced security measures accessible and manageable.&lt;/p&gt;

&lt;p&gt;Given the dynamic nature of cybersecurity, continuous improvement and community feedback are essential. If any inaccuracies are noticed or if there are suggestions for enhancing the security aspects discussed, the community's input would be greatly appreciated.&lt;/p&gt;

</description>
      <category>https</category>
      <category>docker</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Practical PostgreSQL Logical Replication: Setting Up an Experimentation Environment Using Docker</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Sun, 11 Feb 2024 11:56:39 +0000</pubDate>
      <link>https://dev.to/ietxaniz/practical-postgresql-logical-replication-setting-up-an-experimentation-environment-using-docker-4h50</link>
      <guid>https://dev.to/ietxaniz/practical-postgresql-logical-replication-setting-up-an-experimentation-environment-using-docker-4h50</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the world of database management, ensuring data consistency, availability, and scalability is paramount. Among the myriad strategies to achieve these goals, &lt;strong&gt;logical replication&lt;/strong&gt; in PostgreSQL stands out as a powerful feature that allows data to be replicated to different systems in real-time. This not only enhances read performance across distributed databases but also serves as a cornerstone for disaster recovery and almost zero-downtime upgrades.&lt;/p&gt;

&lt;p&gt;Logical replication works by replicating changes at the level of database transactions, providing the flexibility to select which databases, tables, or even rows get replicated. This granular control makes it an invaluable tool for creating highly available systems that can withstand the loss of a primary database or scale horizontally as demand increases. Although this fine-grain control can be useful for some complex scenarios, in this article, we will focus on a setup where all the database tables and rows will be replicated.&lt;/p&gt;

&lt;p&gt;Setting up and experimenting with logical replication can seem daunting. This is where Docker comes into play. By containerizing PostgreSQL instances, Docker allows us to mimic complex, distributed database setups on a single machine, making this advanced feature more approachable for everyone.&lt;/p&gt;

&lt;p&gt;In this article, we will embark on a hands-on journey to understand and implement PostgreSQL logical replication. We'll set up a master database and two replicas within a Dockerized environment, guiding you through the process of configuring logical replication, manipulating data, and observing how PostgreSQL handles data consistency and recovery in real-time. This exploration will not only clarify the process of setting up logical replication but also highlight its potential in real-world scenarios. For those interested in following along with code examples and configurations, the source code for this project is available on GitHub at &lt;a href="https://github.com/ietxaniz/pg-logrepl"&gt;https://github.com/ietxaniz/pg-logrepl&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We Will Build
&lt;/h2&gt;

&lt;p&gt;In this hands-on guide, we'll embark on a fascinating journey to set up a robust PostgreSQL logical replication environment using Docker. Our project is designed to simulate a real-world scenario where data consistency, availability, and scalability are key. Here's what we'll accomplish:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Create Three PostgreSQL Instances&lt;/strong&gt;: Using Docker Compose, we will spin up three separate PostgreSQL instances. This setup will serve as the backbone of our replication environment, providing a practical insight into managing multiple databases in a contained ecosystem.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Configure Logical Replication&lt;/strong&gt;: All instances will be configured to support logical replication. This involves setting one database as the master (publisher) and the other two as replicas (subscribers), establishing a real-time data synchronization framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Schema Synchronization&lt;/strong&gt;: We'll ensure that all three databases start with the same schema, laying the foundation for seamless data replication across our setup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Manipulation and Replication&lt;/strong&gt;: Through a series of data manipulation exercises, we'll demonstrate how changes made to the master database are immediately reflected in the replica databases. This includes adding data and simulating a replica downtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Failover and Recovery Scenarios&lt;/strong&gt;: We'll simulate a failover scenario by killing the master instance and promoting a replica to be the new master. This part of the project will highlight the resilience and flexibility of logical replication in handling unexpected database failures.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Consistency Checks&lt;/strong&gt;: At various stages, we'll verify that data remains consistent across all instances, demonstrating the reliability of PostgreSQL's logical replication mechanism.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Role Reversal and Recovery&lt;/strong&gt;: Finally, we'll bring the original master back online as a replica, completing our exploration of logical replication dynamics and ensuring all databases are synchronized.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Throughout this project, we will follow a sequence of steps designed to provide you with a comprehensive understanding of setting up and managing a logical replication system in PostgreSQL. By the end, you'll have hands-on experience with critical database administration tasks, including configuring replication, handling failovers, and ensuring data consistency across distributed systems.&lt;/p&gt;

&lt;p&gt;For your convenience and to facilitate following along, all the code, configurations, and Docker Compose files used in this guide will be available in a GitHub repository. This will allow you to replicate the setup on your own machine and experiment further with PostgreSQL's logical replication features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Working Environment
&lt;/h2&gt;

&lt;p&gt;The sole prerequisite for this tutorial is having &lt;strong&gt;Docker installed&lt;/strong&gt; on your machine. This guide and accompanying scripts are tailored for Linux environments, providing a smooth experience for Linux users right out of the box. However, the beauty of Docker is its cross-platform compatibility. Therefore, if you're using &lt;strong&gt;macOS&lt;/strong&gt; or &lt;strong&gt;Windows with WSL (Windows Subsystem for Linux)&lt;/strong&gt;, you can still follow along without significant modifications. The versatility of Docker ensures that our setup can be replicated across different operating systems, making it accessible to a broader audience.&lt;/p&gt;

&lt;p&gt;If Docker is not yet installed on your system, you can find detailed installation instructions on the &lt;a href="https://docs.docker.com/get-docker/"&gt;official Docker website&lt;/a&gt;. Ensure Docker is correctly installed and running before proceeding to the next steps of this guide.&lt;/p&gt;

&lt;p&gt;The skills and knowledge you'll gain from this tutorial are not limited to experimental setups or learning environments. The principles of PostgreSQL logical replication, when combined with the power of Docker, have wide applicability in real-world scenarios, especially in &lt;strong&gt;distributed environments across data centers&lt;/strong&gt;. Whether you're looking to enhance data availability, scale your read operations, or set up a robust disaster recovery system, the concepts covered here will provide a solid foundation.&lt;/p&gt;

&lt;p&gt;While we focus on a contained Docker environment for simplicity, the underlying principles can be extrapolated to more complex setups, including instances running on separate nodes in a data center or even across multiple data centers. This makes our guide an invaluable resource for anyone looking to implement logical replication in production environments.&lt;/p&gt;

&lt;p&gt;For the sake of simplicity and to keep our focus on the core concepts of logical replication, this guide will not cover the setup of encryption for data in transit between the master and replica databases. However, it's important to acknowledge that &lt;strong&gt;encryption is a critical aspect of securing data&lt;/strong&gt; in production environments. In real-world applications, ensuring the security of data in transit using SSL/TLS or other encryption methods is essential to protect against eavesdropping and man-in-the-middle attacks.&lt;/p&gt;

&lt;p&gt;While this tutorial does not delve into encryption configurations, you should explore PostgreSQL's documentation on &lt;a href="https://www.postgresql.org/docs/current/ssl-tcp.html"&gt;securing your database&lt;/a&gt; and consider encryption as an integral part of setting up logical replication in a production environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the System
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Docker Compose Setup
&lt;/h3&gt;

&lt;p&gt;To kick off our exploration of PostgreSQL logical replication, we'll start by creating the backbone of our environment: the Docker Compose setup. This setup will include one master and two replica PostgreSQL instances, each running in separate Docker containers. What makes our setup particularly interesting is the use of different PostgreSQL versions for each instance. This approach not only tests the compatibility of logical replication across versions but also simulates a real-world use case for upgrading PostgreSQL instances with minimal downtime.&lt;/p&gt;

&lt;p&gt;Below is the &lt;code&gt;docker-compose.yml&lt;/code&gt; file that defines our PostgreSQL instances:&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16.1-alpine3.19&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;logrepl_pg_master&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;logrepl_pg_master-data:/var/lib/postgresql/data&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;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
  &lt;span class="na"&gt;replica1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15.5-alpine3.19&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;logrepl_pg_replica1&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;logrepl_pg_replica1-data:/var/lib/postgresql/data&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;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
  &lt;span class="na"&gt;replica2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:14.10-alpine3.19&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;logrepl_pg_replica2&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;logrepl_pg_replica2-data:/var/lib/postgresql/data&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;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;logrepl_pg_master-data&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;logrepl_pg_master-data&lt;/span&gt;
  &lt;span class="na"&gt;logrepl_pg_replica1-data&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;logrepl_pg_replica1-data&lt;/span&gt;
  &lt;span class="na"&gt;logrepl_pg_replica2-data&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;logrepl_pg_replica2-data&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration establishes a master database using PostgreSQL 16.1 and two replicas using versions 15.5 and 14.10, respectively. By employing Alpine Linux as the base image, we ensure our setup is lightweight and efficient. Each service is configured with its volume for data persistence, ensuring that data remains intact across container restarts.&lt;/p&gt;

&lt;p&gt;To bring up the databases, create a file named &lt;code&gt;docker-compose.yml&lt;/code&gt; with the content above. Then, in a shell window, execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will start the PostgreSQL instances as defined in the Docker Compose file. You'll see logs in the terminal indicating that the containers are up and running, ready for the next steps of schema creation and logical replication configuration.&lt;/p&gt;

&lt;p&gt;Once our Docker containers are up and running, the next step is crucial: creating identical schemas across all instances. This consistency is vital for ensuring smooth replication from the master to the replicas. For our project, we'll be using a simple yet illustrative schema that includes users, posts, and comments—emulating a basic blogging platform. This schema not only demonstrates the relationships between different data types but also sets the stage for understanding how logical replication handles data synchronization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Schema
&lt;/h3&gt;

&lt;p&gt;The schema for our project is defined as follows:&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="c1"&gt;-- Schema for Users&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&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;username&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&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;email&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&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;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;WITHOUT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;at&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="s1"&gt;'utc'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Schema for Posts&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;post_id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&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;user_id&lt;/span&gt; &lt;span class="nb"&gt;INT&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;title&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&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;content&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;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;WITHOUT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;at&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="s1"&gt;'utc'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;updated_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;WITHOUT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&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;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Schema for Comments&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;comment_id&lt;/span&gt; &lt;span class="nb"&gt;SERIAL&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;post_id&lt;/span&gt; &lt;span class="nb"&gt;INT&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;user_id&lt;/span&gt; &lt;span class="nb"&gt;INT&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;content&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;created_at&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;WITHOUT&lt;/span&gt; &lt;span class="nb"&gt;TIME&lt;/span&gt; &lt;span class="k"&gt;ZONE&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;at&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="s1"&gt;'utc'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&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;post_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="k"&gt;FOREIGN&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;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This schema sets up a relational structure where users can create posts, and both users and posts can have comments, mimicking a real-world application's data model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Schema Application Script
&lt;/h3&gt;

&lt;p&gt;To simplify the schema application across our PostgreSQL instances, we've prepared a script named &lt;code&gt;create-schemas.sh&lt;/code&gt;. This script automates the process of copying the &lt;code&gt;schema.sql&lt;/code&gt; file to each container and executing it against the PostgreSQL service inside. Here's how the script works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Define the database containers&lt;/span&gt;
&lt;span class="nv"&gt;databases&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_master"&lt;/span&gt; &lt;span class="s2"&gt;"logrepl_pg_replica1"&lt;/span&gt; &lt;span class="s2"&gt;"logrepl_pg_replica2"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;schema_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"./schema.sql"&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;db &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;databases&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Copying schema to &lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
    docker &lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$schema_file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;:/tmp/schema.sql"&lt;/span&gt;

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Loading schema in &lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
    docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/schema.sql

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Removing schema file from &lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
    docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; /tmp/schema.sql

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Schema loaded successfully in &lt;/span&gt;&lt;span class="nv"&gt;$db&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To execute this script, ensure it has execute permissions by running &lt;code&gt;chmod +x create-schemas.sh&lt;/code&gt;, then execute it with &lt;code&gt;./create-schemas.sh&lt;/code&gt;. The script will iterate over each defined database container, copy the schema file, execute it, and clean up, ensuring that each database instance is configured with the identical schema needed for our logical replication setup.&lt;/p&gt;

&lt;p&gt;By maintaining schema consistency across the master and replica databases, we ensure that our logical replication process can proceed without any schema-related conflicts, providing a seamless data synchronization experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration for Logical Replication
&lt;/h3&gt;

&lt;p&gt;After setting up our PostgreSQL instances and ensuring they share identical schemas, the next crucial step is to configure them for logical replication. This process requires adjusting specific settings in the PostgreSQL configuration files to enable and optimize the replication process.&lt;/p&gt;

&lt;p&gt;To streamline this configuration process, we've created a script named &lt;code&gt;configure-dbs.sh&lt;/code&gt;. This script automates the adjustments necessary for all instances (master and replicas) to prepare them for logical replication. By configuring the same parameters across all databases, we not only prepare them for their current roles but also allow for the flexibility to change roles in the future, such as converting a replica into a master during failover scenarios or planned upgrades.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Configuration Changes
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;wal_level&lt;/code&gt;&lt;/strong&gt;: Set to &lt;code&gt;logical&lt;/code&gt; to support capturing and replicating changes at the transaction level, rather than at the physical block level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;max_replication_slots&lt;/code&gt;&lt;/strong&gt;: Increased to accommodate the planned number of replicas, ensuring the master retains enough WAL logs for all replicas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;max_wal_senders&lt;/code&gt;&lt;/strong&gt;: Raised to allow more concurrent WAL sender processes, facilitating efficient data streaming to replicas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replication Permissions in &lt;code&gt;pg_hba.conf&lt;/code&gt;&lt;/strong&gt;: Configured to grant necessary connection permissions for replication purposes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Configuration Script
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Script to configure PostgreSQL instances for logical replication&lt;/span&gt;

&lt;span class="nv"&gt;max_number_of_replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4
&lt;span class="nv"&gt;max_wal_senders&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8

&lt;span class="c"&gt;# Define all PostgreSQL instances&lt;/span&gt;
&lt;span class="nv"&gt;databases&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_master"&lt;/span&gt; &lt;span class="s2"&gt;"logrepl_pg_replica1"&lt;/span&gt; &lt;span class="s2"&gt;"logrepl_pg_replica2"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;db &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;databases&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c"&gt;# Apply configuration changes&lt;/span&gt;
    ...
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c"&gt;# Reminder to execute with caution, especially in production environments.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before running &lt;code&gt;configure-dbs.sh&lt;/code&gt;, ensure it's executable with &lt;code&gt;chmod +x configure-dbs.sh&lt;/code&gt;. Execute the script to apply configuration changes across all instances. Designed for efficiency and safety, this script reduces complexity and minimizes the potential for configuration errors, setting the stage for a seamless replication process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Replication
&lt;/h3&gt;

&lt;p&gt;After configuring our PostgreSQL instances for logical replication, the next step is to establish the replication relationship itself. This involves defining one database as the master (or publisher) and the others as replicas (or subscribers). We achieve this through the &lt;code&gt;configure-replication.sh&lt;/code&gt; script, which automates the setup, ensuring changes made in the master database are seamlessly replicated to &lt;code&gt;logrepl_pg_replica1&lt;/code&gt; and &lt;code&gt;logrepl_pg_replica2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Define the master database and the replicas&lt;/span&gt;
&lt;span class="nv"&gt;master_db&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_master"&lt;/span&gt;
&lt;span class="nv"&gt;replicas&lt;/span&gt;&lt;span class="o"&gt;=(&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_replica1"&lt;/span&gt; &lt;span class="s2"&gt;"logrepl_pg_replica2"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Configure the master database&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Configuring &lt;/span&gt;&lt;span class="nv"&gt;$master_db&lt;/span&gt;&lt;span class="s2"&gt; as master..."&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$master_db&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"DROP PUBLICATION IF EXISTS my_publication;"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$master_db&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"CREATE PUBLICATION my_publication FOR ALL TABLES;"&lt;/span&gt;

&lt;span class="c"&gt;# Configure each replica to follow the master&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;replica &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;replicas&lt;/span&gt;&lt;span class="p"&gt;[@]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Configuring &lt;/span&gt;&lt;span class="nv"&gt;$replica&lt;/span&gt;&lt;span class="s2"&gt; to replicate from &lt;/span&gt;&lt;span class="nv"&gt;$master_db&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;

    &lt;span class="c"&gt;# Construct the connection string&lt;/span&gt;
    &lt;span class="nv"&gt;conninfo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"host=&lt;/span&gt;&lt;span class="nv"&gt;$master_db&lt;/span&gt;&lt;span class="s2"&gt; port=5432 user=postgres password=postgres dbname=postgres"&lt;/span&gt;

    &lt;span class="c"&gt;# Configure the subscription on the replica&lt;/span&gt;
    docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$replica&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"DROP SUBSCRIPTION IF EXISTS &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;replica&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_subscription;"&lt;/span&gt;
    docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$replica&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"CREATE SUBSCRIPTION &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;replica&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_subscription CONNECTION 'dbname=postgres host=&lt;/span&gt;&lt;span class="nv"&gt;$master_db&lt;/span&gt;&lt;span class="s2"&gt; user=postgres password=postgres' PUBLICATION my_publication;"&lt;/span&gt;

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$replica&lt;/span&gt;&lt;span class="s2"&gt; configured to replicate from &lt;/span&gt;&lt;span class="nv"&gt;$master_db&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
&lt;span class="k"&gt;done

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Master and replicas configured successfully for logical replication."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script starts by configuring &lt;code&gt;logrepl_pg_master&lt;/code&gt; as the master database. It does so by dropping any existing publication named &lt;code&gt;my_publication&lt;/code&gt; (to avoid conflicts) and then creating a new publication that includes all tables. This publication acts as the source of data changes that will be replicated to the subscribers. For each replica, the script creates a subscription to the master's publication. It first removes any existing subscription to avoid conflicts, then establishes a new subscription using the connection information to the master database. This subscription mechanism is what allows the replicas to receive and apply changes from the master.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Commands Explained
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DROP PUBLICATION IF EXISTS my_publication;&lt;/code&gt;: Ensures idempotency by removing the existing publication before creating a new one.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CREATE PUBLICATION my_publication FOR ALL TABLES;&lt;/code&gt;: Creates a new publication on the master that includes all tables, making them available for replication.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DROP SUBSCRIPTION IF EXISTS ${replica}_subscription;&lt;/code&gt;: Removes any existing subscription on the replica.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CREATE SUBSCRIPTION ${replica}_subscription CONNECTION '...' PUBLICATION my_publication;&lt;/code&gt;: Establishes a new subscription on each replica to the master's publication, enabling data replication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data Manipulation and Replication Process
&lt;/h2&gt;

&lt;p&gt;Now that we've set up our PostgreSQL logical replication environment, it's time to see it in action. We'll begin by demonstrating how data added to the master database is automatically replicated across all connected replicas. This real-time synchronization is the heart of logical replication, ensuring data consistency and availability across our distributed database system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Data to the Master
&lt;/h3&gt;

&lt;p&gt;Let's start by inserting a new user into the &lt;code&gt;users&lt;/code&gt; table on the master database. We'll execute the following command in a shell environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_master psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"INSERT INTO users (username, email) VALUES ('newuser', 'newuser@example.com');"&lt;/span&gt;
INSERT 0 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command inserts a new row with the username &lt;code&gt;newuser&lt;/code&gt; and the email &lt;code&gt;newuser@example.com&lt;/code&gt; into the &lt;code&gt;users&lt;/code&gt; table. The &lt;code&gt;INSERT 0 1&lt;/code&gt; response indicates that the operation was successful and one row was added.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verifying Replication on the Replicas
&lt;/h3&gt;

&lt;p&gt;Next, we'll verify that this new row has been replicated to both replicas. To do this, we'll query the &lt;code&gt;users&lt;/code&gt; table on each replica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email        |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+---------------------+----------------------------
       1 | newuser  | newuser@example.com | 2024-02-11 10:08:08.116556
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica2 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email        |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+---------------------+----------------------------
       1 | newuser  | newuser@example.com | 2024-02-11 10:08:08.116556
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can observe, the &lt;code&gt;users&lt;/code&gt; table on both &lt;code&gt;logrepl_pg_replica1&lt;/code&gt; and &lt;code&gt;logrepl_pg_replica2&lt;/code&gt; instances reflects the data we inserted into the master database. This immediate synchronization showcases the efficiency and reliability of PostgreSQL's logical replication.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching Off One of the Replicas
&lt;/h3&gt;

&lt;p&gt;To further test the resilience of our logical replication setup, let's simulate a scenario where one of the replicas (&lt;code&gt;logrepl_pg_replica2&lt;/code&gt;) goes offline. This step will help us understand how PostgreSQL handles replication when a subscriber is temporarily unavailable.&lt;/p&gt;

&lt;p&gt;First, we'll stop the &lt;code&gt;logrepl_pg_replica2&lt;/code&gt; container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker stop logrepl_pg_replica2
logrepl_pg_replica2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With &lt;code&gt;logrepl_pg_replica2&lt;/code&gt; offline, let's insert a new user into the &lt;code&gt;users&lt;/code&gt; table on the master database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_master psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"INSERT INTO users (username, email) VALUES ('newuser2', 'newuser2@example.com');"&lt;/span&gt;
INSERT 0 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's verify that this new data is replicated to &lt;code&gt;logrepl_pg_replica1&lt;/code&gt;, which is still online:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
&lt;span class="o"&gt;(&lt;/span&gt;2 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As expected, &lt;code&gt;logrepl_pg_replica1&lt;/code&gt; has successfully received and applied the new data. However, since &lt;code&gt;logrepl_pg_replica2&lt;/code&gt; is offline, it won't have this latest update. Attempting to query &lt;code&gt;logrepl_pg_replica2&lt;/code&gt; results in an error, as the container is not running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica2 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
Error response from daemon: container 70cb8a4ff8f10ac047cbfd6b531b23cf88fe4def0c4ef1521187027ee343f173 is not running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step effectively demonstrates the robustness of our logical replication setup in handling scenarios where a replica may become temporarily unavailable. Next, we'll explore how PostgreSQL catches up the offline replica once it's back online, ensuring data consistency across the entire replication system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching On Replica2
&lt;/h3&gt;

&lt;p&gt;After demonstrating the behavior of our logical replication setup with one replica offline, let's proceed to bring &lt;code&gt;logrepl_pg_replica2&lt;/code&gt; back online. This step is crucial to observe how PostgreSQL handles the synchronization process for replicas that were temporarily unavailable and ensures they catch up with the master's current state.&lt;/p&gt;

&lt;p&gt;To restart &lt;code&gt;logrepl_pg_replica2&lt;/code&gt;, we simply use the Docker command to start the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker start logrepl_pg_replica2
logrepl_pg_replica2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After giving it a moment to initialize and reestablish its connection to the master, we then check the &lt;code&gt;users&lt;/code&gt; table to confirm that &lt;code&gt;logrepl_pg_replica2&lt;/code&gt; has successfully synchronized and now contains the same data as the master and the other replica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;2
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica2 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
&lt;span class="o"&gt;(&lt;/span&gt;2 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the output shows, &lt;code&gt;logrepl_pg_replica2&lt;/code&gt; automatically updated its data to reflect the current state of the master database upon reconnection. This behavior underscores the powerful automatic recovery and synchronization capabilities of PostgreSQL's logical replication mechanism. Without any manual intervention, the replica was able to catch up with the changes it missed while offline, ensuring data consistency across our distributed database system.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding More Users in the New State
&lt;/h3&gt;

&lt;p&gt;With our replication setup now fully operational and having demonstrated its resilience to replica downtime, we proceed to test the continuous synchronization capabilities by adding another user to the master database. This step will help us verify that all databases, including the previously offline replica, are correctly synchronized in real time.&lt;/p&gt;

&lt;p&gt;We add a new user, &lt;code&gt;newuser3&lt;/code&gt;, to the &lt;code&gt;users&lt;/code&gt; table on the master database and confirm the insertion was successful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_master psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"INSERT INTO users (username, email) VALUES ('newuser3', 'newuser3@example.com');"&lt;/span&gt;
INSERT 0 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we ensure that this new data is accurately reflected across both replicas, in addition to the master, by querying the &lt;code&gt;users&lt;/code&gt; table on each database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_master psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
&lt;span class="o"&gt;(&lt;/span&gt;3 rows&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
&lt;span class="o"&gt;(&lt;/span&gt;3 rows&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica2 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
&lt;span class="o"&gt;(&lt;/span&gt;3 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As the output indicates, &lt;code&gt;newuser3&lt;/code&gt; is now present in the &lt;code&gt;users&lt;/code&gt; table across all instances (&lt;code&gt;logrepl_pg_master&lt;/code&gt;, &lt;code&gt;logrepl_pg_replica1&lt;/code&gt;, and &lt;code&gt;logrepl_pg_replica2&lt;/code&gt;), demonstrating that the logical replication system efficiently synchronizes data in real-time across the entire distributed environment.&lt;/p&gt;

&lt;p&gt;This exercise confirms the robustness and reliability of our PostgreSQL logical replication setup. It showcases not only the system's ability to handle disruptions but also its capability to maintain data consistency and availability seamlessly across multiple database instances, ensuring that each part of our system is always up-to-date with the latest data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching of Master and Making Replica1 New Master
&lt;/h3&gt;

&lt;p&gt;In real-world scenarios, it's essential to prepare for situations where the master database might go down or need to be taken offline for maintenance. In such cases, promoting one of the replicas to be the new master ensures continuity of operations and data availability. Our next sequence of steps demonstrates how to handle this transition smoothly, using &lt;code&gt;step07.sh&lt;/code&gt; to automate the process.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Define the services&lt;/span&gt;
&lt;span class="nv"&gt;new_master&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_replica1"&lt;/span&gt;
&lt;span class="nv"&gt;remaining_replica&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_replica2"&lt;/span&gt;

&lt;span class="c"&gt;# Stop the old master&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Stopping the old master: &lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
docker stop &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="c"&gt;# Wait for a second to ensure the stop command fully processes&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;1

&lt;span class="c"&gt;# Disable subscriptions on replica1 and replica2 without dropping them&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Disabling subscriptions on &lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt; and &lt;/span&gt;&lt;span class="nv"&gt;$remaining_replica&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"ALTER SUBSCRIPTION &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;new_master&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_subscription DISABLE; ALTER SUBSCRIPTION &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;new_master&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_subscription SET (slot_name = NONE);"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$remaining_replica&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"ALTER SUBSCRIPTION &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;remaining_replica&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_subscription DISABLE; ALTER SUBSCRIPTION &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;remaining_replica&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_subscription SET (slot_name = NONE);"&lt;/span&gt;


&lt;span class="c"&gt;# update postgresql secuences on the new master to be&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT setval('users_user_id_seq', COALESCE((SELECT MAX(user_id) FROM users), 0) + 1, false);"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT setval('posts_post_id_seq', COALESCE((SELECT MAX(post_id) FROM posts), 0) + 1, false);"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT setval('comments_comment_id_seq', COALESCE((SELECT MAX(comment_id) FROM comments), 0) + 1, false);"&lt;/span&gt;

&lt;span class="c"&gt;# Ensure replica2 starts with a clean state&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Resetting data on &lt;/span&gt;&lt;span class="nv"&gt;$remaining_replica&lt;/span&gt;&lt;span class="s2"&gt; to prepare for replication..."&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$remaining_replica&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"TRUNCATE TABLE users, posts, comments RESTART IDENTITY CASCADE;"&lt;/span&gt;

&lt;span class="c"&gt;# Continue with the creation of the new publication and subscription as before&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Creating new publication on &lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"CREATE PUBLICATION new_master_publication FOR ALL TABLES;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Configuring &lt;/span&gt;&lt;span class="nv"&gt;$remaining_replica&lt;/span&gt;&lt;span class="s2"&gt; to replicate from &lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$remaining_replica&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"CREATE SUBSCRIPTION replica2_new_subscription CONNECTION 'dbname=postgres host=&lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt; user=postgres password=postgres' PUBLICATION new_master_publication;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Replication reconfiguration complete."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Key Steps in the Transition Process
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stopping the Old Master&lt;/strong&gt;: We begin by stopping the current master database to simulate its failure or planned downtime.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Disabling Subscriptions&lt;/strong&gt;: Subscriptions on the replicas are temporarily disabled to prevent them from trying to replicate data from the now-offline master. This is a crucial step to avoid replication conflicts during the transition.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Updating Sequences&lt;/strong&gt;: On the new master (logrepl_pg_replica1), we update the sequences for all tables to ensure that new records will have unique identifiers, avoiding conflicts with existing data.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resetting Data on the Remaining Replica&lt;/strong&gt;: To prepare logrepl_pg_replica2 for replication from the new master, we reset its data. This step is essential to ensure that it starts with a clean slate, eliminating the risk of id conflicts and data discrepancies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reconfiguring Replication&lt;/strong&gt;: We create a new publication on the new master and configure the remaining replica to subscribe to this publication, effectively re-establishing the logical replication setup with logrepl_pg_replica1 now acting as the master.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After executing next sequence, we validate the replication setup by inserting a new user into the users table on the new master (&lt;code&gt;logrepl_pg_replica1&lt;/code&gt;) and verifying that this change is replicated to &lt;code&gt;logrepl_pg_replica2&lt;/code&gt;. The successful replication of this new record to both replicas confirms the correct reconfiguration of the logical replication setup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$$&lt;/span&gt; docker stop logrepl_pg_master
logrepl_pg_master
&lt;span class="nv"&gt;$$&lt;/span&gt; &lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="nv"&gt;$$&lt;/span&gt; ./step07.sh
Stopping the old master: ...
Error response from daemon: page not found
Disabling subscriptions on logrepl_pg_replica1 and logrepl_pg_replica2...
ALTER SUBSCRIPTION
ALTER SUBSCRIPTION
ALTER SUBSCRIPTION
 setval 
&lt;span class="nt"&gt;--------&lt;/span&gt;
      4
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;

 setval 
&lt;span class="nt"&gt;--------&lt;/span&gt;
      1
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;

 setval 
&lt;span class="nt"&gt;--------&lt;/span&gt;
      1
&lt;span class="o"&gt;(&lt;/span&gt;1 row&lt;span class="o"&gt;)&lt;/span&gt;

Resetting data on logrepl_pg_replica2 to prepare &lt;span class="k"&gt;for &lt;/span&gt;replication...
TRUNCATE TABLE
Creating new publication on logrepl_pg_replica1...
CREATE PUBLICATION
Configuring logrepl_pg_replica2 to replicate from logrepl_pg_replica1...
NOTICE:  created replication slot &lt;span class="s2"&gt;"replica2_new_subscription"&lt;/span&gt; on publisher
CREATE SUBSCRIPTION
Replication reconfiguration complete.
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"INSERT INTO users (username, email) VALUES ('newuser4', 'newuser4@example.com');"&lt;/span&gt;
INSERT 0 1
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_master psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
Error response from daemon: container b85f8d95443abae3f898c4e28d3afc3e319730ade2a098e94cc7b0e646ee7ac8 is not running
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
&lt;span class="o"&gt;(&lt;/span&gt;4 rows&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica2 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
&lt;span class="o"&gt;(&lt;/span&gt;4 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Considerations and Potential Sources of Failure
&lt;/h4&gt;

&lt;p&gt;Before the master goes down, it's crucial to ensure that all replicas are fully synchronized. Any discrepancy between the data on logrepl_pg_replica1 and logrepl_pg_replica2 at the time of the switch can lead to inconsistencies, as the new master will begin replicating from its current state. Updating all sequences on the new master is vital to prevent conflicts caused by overlapping identifiers. This step ensures that new inserts on the new master will not conflict with existing data. The process of stopping the master should be controlled and synchronized with the replicas to minimize the risk of data inconsistency or loss.&lt;/p&gt;

&lt;p&gt;By carefully following these steps and considerations, we can effectively manage the transition of the master role to a replica, maintaining data integrity and availability. This process highlights the flexibility and resilience of PostgreSQL's logical replication mechanism, allowing for robust database management strategies in distributed environments.&lt;/p&gt;

&lt;p&gt;In failover scenarios ensuring that all replicas have same data is not so easy to manage, as some replicas could not be fully updated, so a carefull strategy should be choosen for this scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching the Master Back On: Challenges and Solutions
&lt;/h3&gt;

&lt;h4&gt;
  
  
  The Unexpected Challenge
&lt;/h4&gt;

&lt;p&gt;When attempting to reintegrate the original master (&lt;code&gt;logrepl_pg_master&lt;/code&gt;) back into our replication setup as a subscriber, the process didn't proceed as smoothly as anticipated. Despite successfully configuring it to subscribe to &lt;code&gt;logrepl_pg_replica1&lt;/code&gt; (the new master), data updates from the new master weren't replicated to the old master as expected. This issue underscored the complexities involved in reversing replication roles within a PostgreSQL logical replication setup.&lt;/p&gt;

&lt;p&gt;This was the script I used to subscribe the old master to the new master:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;old_master&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_master"&lt;/span&gt;
&lt;span class="nv"&gt;new_master&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_replica1"&lt;/span&gt;
&lt;span class="nv"&gt;old_master_subscription&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my_subscription"&lt;/span&gt;

docker start &lt;span class="nv"&gt;$old_master&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;1

&lt;span class="c"&gt;# Disable any outgoing replication from the old master&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Disabling any publications on &lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"DROP PUBLICATION IF EXISTS my_publication;"&lt;/span&gt;

&lt;span class="c"&gt;# Create a new subscription on the old master to the new master's publication&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"DROP SUBSCRIPTION IF EXISTS &lt;/span&gt;&lt;span class="nv"&gt;$old_master_subscription&lt;/span&gt;&lt;span class="s2"&gt;;"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"CREATE SUBSCRIPTION &lt;/span&gt;&lt;span class="nv"&gt;$old_master_subscription&lt;/span&gt;&lt;span class="s2"&gt; CONNECTION 'dbname=postgres host=&lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt; user=postgres password=postgres' PUBLICATION new_master_publication;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Subscription setup complete. &lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt; is now a subscriber of &lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But, then I realised that data was not being updated in master:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_master psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
&lt;span class="o"&gt;(&lt;/span&gt;3 rows&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
&lt;span class="o"&gt;(&lt;/span&gt;4 rows&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica2 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
&lt;span class="o"&gt;(&lt;/span&gt;4 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I checked log messages and found out the next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;logrepl_pg_replica1  | 2024-02-11 10:51:19.017 UTC &lt;span class="o"&gt;[&lt;/span&gt;230] LOG:  logical decoding found consistent point at 0/158FF30
logrepl_pg_replica1  | 2024-02-11 10:51:19.017 UTC &lt;span class="o"&gt;[&lt;/span&gt;230] DETAIL:  There are no running transactions.
logrepl_pg_replica1  | 2024-02-11 10:51:19.017 UTC &lt;span class="o"&gt;[&lt;/span&gt;230] STATEMENT:  CREATE_REPLICATION_SLOT &lt;span class="s2"&gt;"pg_16436_sync_16385_7334283988469985309"&lt;/span&gt; LOGICAL pgoutput &lt;span class="o"&gt;(&lt;/span&gt;SNAPSHOT &lt;span class="s1"&gt;'use'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
logrepl_pg_master    | 2024-02-11 10:51:19.079 UTC &lt;span class="o"&gt;[&lt;/span&gt;67] ERROR:  duplicate key value violates unique constraint &lt;span class="s2"&gt;"users_pkey"&lt;/span&gt;
logrepl_pg_master    | 2024-02-11 10:51:19.079 UTC &lt;span class="o"&gt;[&lt;/span&gt;67] DETAIL:  Key &lt;span class="o"&gt;(&lt;/span&gt;user_id&lt;span class="o"&gt;)=(&lt;/span&gt;1&lt;span class="o"&gt;)&lt;/span&gt; already exists.
logrepl_pg_master    | 2024-02-11 10:51:19.079 UTC &lt;span class="o"&gt;[&lt;/span&gt;67] CONTEXT:  COPY &lt;span class="nb"&gt;users&lt;/span&gt;, line 1
logrepl_pg_master    | 2024-02-11 10:51:19.084 UTC &lt;span class="o"&gt;[&lt;/span&gt;1] LOG:  background worker &lt;span class="s2"&gt;"logical replication worker"&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;PID 67&lt;span class="o"&gt;)&lt;/span&gt; exited with &lt;span class="nb"&gt;exit &lt;/span&gt;code 1
logrepl_pg_master    | 2024-02-11 10:51:24.096 UTC &lt;span class="o"&gt;[&lt;/span&gt;68] LOG:  logical replication table synchronization worker &lt;span class="k"&gt;for &lt;/span&gt;subscription &lt;span class="s2"&gt;"my_subscription"&lt;/span&gt;, table &lt;span class="s2"&gt;"users"&lt;/span&gt; has started
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So this means that now that master has subscribed to replica, the system is trying to transmit full database data. I could have reseted master subscription in order to start listening from now on using next instruction but this would mean that master would miss database changes made from the time it was off till the time it is on again:&lt;/p&gt;

&lt;h4&gt;
  
  
  Resolution: Starting from Scratch
&lt;/h4&gt;

&lt;p&gt;To resolve the synchronization issues, a decisive approach was taken: restarting the original master from scratch. This involved removing the existing Docker container and volume for &lt;code&gt;logrepl_pg_master&lt;/code&gt;, then recreating and reconfiguring it from the ground up. This process guaranteed that the old master, now a subscriber, was perfectly in sync with the current state of the new master, effectively making it an up-to-date replica.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;old_master&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_master"&lt;/span&gt;
&lt;span class="nv"&gt;new_master&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"logrepl_pg_replica1"&lt;/span&gt;
&lt;span class="nv"&gt;old_master_subscription&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my_subscription"&lt;/span&gt;
&lt;span class="nv"&gt;max_number_of_replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4
&lt;span class="nv"&gt;max_wal_senders&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8

docker stop &lt;span class="nv"&gt;$old_master&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;1
docker &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nv"&gt;$old_master&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;1
docker volume &lt;span class="nb"&gt;rm &lt;/span&gt;logrepl_pg_master-data
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;2
docker &lt;span class="nb"&gt;cp&lt;/span&gt; ./schema.sql &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;:/tmp/schema.sql"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nv"&gt;$old_master&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/schema.sql
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nv"&gt;$old_master&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; /tmp/schema.sql

docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"sed -i 's/^#*wal_level .*&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="s2"&gt;wal_level = logical/' /var/lib/postgresql/data/postgresql.conf"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"sed -i 's/^#*max_replication_slots .*&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="s2"&gt;max_replication_slots = &lt;/span&gt;&lt;span class="nv"&gt;$max_number_of_replicas&lt;/span&gt;&lt;span class="s2"&gt;/' /var/lib/postgresql/data/postgresql.conf"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"sed -i 's/^#*max_wal_senders .*&lt;/span&gt;&lt;span class="nv"&gt;$/&lt;/span&gt;&lt;span class="s2"&gt;max_wal_senders = &lt;/span&gt;&lt;span class="nv"&gt;$max_wal_senders&lt;/span&gt;&lt;span class="s2"&gt;/' /var/lib/postgresql/data/postgresql.conf"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; bash &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"grep -qxF 'host replication all all md5' /var/lib/postgresql/data/pg_hba.conf || echo 'host replication all all md5' &amp;gt;&amp;gt; /var/lib/postgresql/data/pg_hba.conf"&lt;/span&gt;
docker restart &lt;span class="nv"&gt;$old_master&lt;/span&gt;

&lt;span class="nb"&gt;sleep &lt;/span&gt;2

&lt;span class="c"&gt;# Disable any outgoing replication from the old master&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Disabling any publications on &lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;..."&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"DROP PUBLICATION IF EXISTS my_publication;"&lt;/span&gt;

&lt;span class="c"&gt;# Remove previous replica subscriptions of master in replica1&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT pg_drop_replication_slot('my_subscription');"&lt;/span&gt;


&lt;span class="c"&gt;# Create a new subscription on the old master to the new master's publication&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"DROP SUBSCRIPTION IF EXISTS &lt;/span&gt;&lt;span class="nv"&gt;$old_master_subscription&lt;/span&gt;&lt;span class="s2"&gt;;"&lt;/span&gt;
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"CREATE SUBSCRIPTION &lt;/span&gt;&lt;span class="nv"&gt;$old_master_subscription&lt;/span&gt;&lt;span class="s2"&gt; CONNECTION 'dbname=postgres host=&lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt; user=postgres password=postgres' PUBLICATION new_master_publication;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Subscription setup complete. &lt;/span&gt;&lt;span class="nv"&gt;$old_master&lt;/span&gt;&lt;span class="s2"&gt; is now a subscriber of &lt;/span&gt;&lt;span class="nv"&gt;$new_master&lt;/span&gt;&lt;span class="s2"&gt;."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After some time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_master psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
&lt;span class="o"&gt;(&lt;/span&gt;4 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
&lt;span class="o"&gt;(&lt;/span&gt;4 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica2 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
&lt;span class="o"&gt;(&lt;/span&gt;4 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if now we add another row in replica1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"INSERT INTO users (username, email) VALUES ('newuser5', 'newuser5@example.com');"&lt;/span&gt;
INSERT 0 1
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sleep &lt;/span&gt;1
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_master psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
       5 | newuser5 | newuser5@example.com | 2024-02-11 11:17:46.730413
&lt;span class="o"&gt;(&lt;/span&gt;5 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica1 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
       5 | newuser5 | newuser5@example.com | 2024-02-11 11:17:46.730413
&lt;span class="o"&gt;(&lt;/span&gt;5 rows&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; logrepl_pg_replica2 psql &lt;span class="nt"&gt;-U&lt;/span&gt; postgres &lt;span class="nt"&gt;-d&lt;/span&gt; postgres &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"SELECT * FROM users;"&lt;/span&gt;
 user_id | username |        email         |         created_at         
&lt;span class="nt"&gt;---------&lt;/span&gt;+----------+----------------------+----------------------------
       1 | newuser  | newuser@example.com  | 2024-02-11 10:08:08.116556
       2 | newuser2 | newuser2@example.com | 2024-02-11 10:13:38.786147
       3 | newuser3 | newuser3@example.com | 2024-02-11 10:20:31.714676
       4 | newuser4 | newuser4@example.com | 2024-02-11 10:26:50.874549
       5 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach, while drastic, ensured data integrity and consistency across the replication setup. It highlighted a key advantage of containerized environments—the ability to rapidly rebuild and redeploy components of your infrastructure with confidence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reflections and Future Directions
&lt;/h3&gt;

&lt;p&gt;The challenges encountered while switching the master back on have led to valuable insights:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preparation for Role Reversal&lt;/strong&gt;: The need for thorough preparation and clear strategies when reversing roles in a logical replication setup. This includes ensuring data consistency and understanding the implications of such changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilience through Rebuilding&lt;/strong&gt;: The effectiveness of starting from scratch as a means to ensure an accurate and reliable replication setup. While not always ideal, this approach can be a reliable fallback strategy in complex scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exploring Alternative Approaches&lt;/strong&gt;: Inspired by these challenges, I am considering alternative procedures for switching off and replacing the master without the need to replicate the entire database from scratch. This exploration aims to refine our strategies for managing PostgreSQL logical replication, making the process more efficient and less disruptive.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In light of these experiences, I plan to conduct further tests and research into alternative strategies for managing master role transitions in logical replication setups. If successful, these findings will be the subject of a forthcoming article, aimed at providing even more robust and efficient methods for managing PostgreSQL replication environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions and Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Our journey through the intricacies of PostgreSQL logical replication, set within a Dockerized environment, has shed light on vital aspects of database management, including data consistency, availability, and scalability. This hands-on guide underscored the significance of logical replication in bolstering system resilience and adaptability, proving its worth in scenarios demanding disaster recovery and near-zero downtime upgrades.&lt;/p&gt;

&lt;p&gt;The granular control offered by logical replication, enabling selective synchronization of databases, tables, or rows, empowers administrators to devise customized strategies that align with specific operational needs. Docker's role in demystifying the deployment and management of complex, distributed database systems has been pivotal, rendering sophisticated features like logical replication more approachable and manageable.&lt;/p&gt;

&lt;p&gt;The setup's resilience in the face of replica downtimes, coupled with its capacity for smooth role reversals amid failovers, accentuates the paramount importance of foresight and meticulous planning in database management. The imperative to maintain data consistency across all instances, particularly through and beyond failover events, emerged as a central theme, highlighting the challenges that necessitate a systematic approach to managing role transitions and system updates.&lt;/p&gt;

&lt;p&gt;While this exploration has been revealing, it also paves the way for further inquiry, especially concerning the optimization of master role transitions and the reduction of associated downtime. The difficulties experienced in reintegrating the original master as a subscriber have kindled interest in devising strategies that are both more efficient and less intrusive.&lt;/p&gt;

&lt;p&gt;Motivated by these challenges, we are now poised to delve into alternative methodologies for handling master role changes without resorting to complete database replication from scratch. This forthcoming endeavor aims to enhance our logical replication management techniques, emphasizing operational efficiency and minimal disruption.&lt;/p&gt;

&lt;p&gt;In wrapping up, our foray into the domain of PostgreSQL logical replication within a Docker framework has not only broadened our comprehension of this potent functionality but also underscored the perennial value of continuous learning and refinement in database management practices. This journey highlights the evolving nature of technology and our relentless pursuit of increasingly sophisticated and effective solutions within the dynamic realm of database administration.&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>tutorial</category>
      <category>docker</category>
      <category>database</category>
    </item>
    <item>
      <title>Setting Up VSCode Development Environments with Docker on Linux</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Sat, 20 Jan 2024 18:50:57 +0000</pubDate>
      <link>https://dev.to/ietxaniz/setting-up-vscode-development-environments-with-docker-on-linux-1gn6</link>
      <guid>https://dev.to/ietxaniz/setting-up-vscode-development-environments-with-docker-on-linux-1gn6</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the evolving landscape of software development, the efficiency and reliability of your development environment can significantly impact productivity and collaboration. The &lt;a href="https://github.com/ietxaniz/vscode-in-docker" rel="noopener noreferrer"&gt;VSCode in Docker&lt;/a&gt; project recognizes this, offering a versatile approach to set up development environments using Docker to run Visual Studio Code (VSCode) on Linux. This method excels in creating isolated, secure, and highly reproducible development spaces, tailored to the diverse needs of modern developers.&lt;/p&gt;

&lt;p&gt;This article delves into the world of Dockerized VSCode environments, underscoring benefits like enhanced security, resource efficiency, and consistency across multiple machines. A unique advantage of this setup is its ability to segregate development environments based on project or language-specific needs. This isolation not only simplifies environment management but also reduces the clutter of unnecessary extensions, avoiding unproductive distractions or annoying notifications.&lt;/p&gt;

&lt;p&gt;The project provides Docker images such as &lt;code&gt;inigoetxaniz/vscode-base&lt;/code&gt;, &lt;code&gt;inigoetxaniz/vscode-go&lt;/code&gt;, and &lt;code&gt;inigoetxaniz/vscode-ext-devel&lt;/code&gt;, each catering to different development requirements. This setup is ideal for testing new extensions in a safe, controlled environment, without risking your primary development setup. It also allows for simultaneously running multiple VSCode instances with different configurations and access controls – imagine having separate instances for Node.js and Rust, each with its own tailored settings and themes.&lt;/p&gt;

&lt;p&gt;In the upcoming sections, we will explore the advantages of using Dockerized VSCode environments, offer a step-by-step guide for setup, and discuss practical use cases and customization options. Join us as we dive in to discover how Docker can revolutionize your VSCode experience on Linux, enhancing productivity and offering unparalleled flexibility in your development workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of Dockerized VSCode Environments
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Getting Started
&lt;/h3&gt;

&lt;p&gt;Before diving into the setup of Dockerized VSCode environments, it's important to cover the basic requirements. The primary requirement is a Linux-based system with Docker installed. For the purposes of this guide and the development of the Dockerized VSCode project, Ubuntu 22.04 LTS (Long-Term Support) with the GNOME desktop environment has been used as the testing platform. This version of Ubuntu provides a stable and up-to-date foundation, ensuring compatibility and performance for the Dockerized VSCode environments.&lt;/p&gt;

&lt;p&gt;While this guide won't delve into the specifics of installing Docker on Ubuntu, users new to Docker can follow the comprehensive installation instructions provided by Docker itself at &lt;a href="https://docs.docker.com/engine/install/ubuntu/" rel="noopener noreferrer"&gt;Docker Installation Guide for Ubuntu&lt;/a&gt;. These instructions are clear, detailed, and cater to various setup preferences, ensuring you can get Docker up and running smoothly on your system.&lt;/p&gt;

&lt;p&gt;It's important to note that while this guide focuses on Ubuntu 22.04, the principles and steps should be applicable to other Linux distributions with minor adjustments. However, the choice of Ubuntu 22.04 comes with the advantage of long-term support and widespread use, making it a reliable choice for a development environment. &lt;/p&gt;

&lt;h3&gt;
  
  
  Isolation and Security
&lt;/h3&gt;

&lt;p&gt;One of the standout features of using Dockerized environments for Visual Studio Code (VSCode) is the enhanced level of isolation and security it provides. This benefit is primarily due to the sandboxing nature of Docker containers. In a sandboxed environment, the application (in this case, VSCode) operates in a separate space, isolated from the host system. This isolation plays a crucial role in enhancing security, especially when dealing with untrusted extensions or experimental code.&lt;/p&gt;

&lt;p&gt;In a typical setup without Docker, extensions installed in VSCode have access to the host system, which can pose security risks, especially if the extensions are not from trusted sources. In contrast, with Dockerized VSCode environments, VSCode instances only have access to the directories explicitly mounted as volumes in the Docker container. This design means that you, as the user, have full control over which folders the VSCode instance and its extensions can access.&lt;/p&gt;

&lt;p&gt;A key security advantage here is that any operation, installation, or changes made within the Dockerized VSCode environment stay within the container. These changes do not affect the host machine directly. For instance, if you're experimenting with a new VSCode extension and it behaves unexpectedly or maliciously, its impact is confined within the container. The host system remains unaffected, safeguarding your primary development setup.&lt;/p&gt;

&lt;p&gt;This containment offers a safe playground for testing and using extensions or running experimental code. If something goes wrong, the effects are limited to the container, which can be easily stopped, removed, or reset. Essentially, Docker acts as a robust barrier, ensuring that your host system's integrity and security are maintained, regardless of the activities within the VSCode container.&lt;/p&gt;

&lt;p&gt;Furthermore, this isolation ensures that your development environment remains clean and uncluttered. Since nothing inside the Docker container is installed on the host machine, it avoids potential conflicts or pollution of the host's environment. This separation is particularly beneficial for maintaining a stable and secure development environment, especially in scenarios where multiple projects or development contexts are in play.&lt;/p&gt;

&lt;p&gt;In summary, the isolation and security provided by Dockerized VSCode environments represent a significant step forward in safe and efficient software development practices. It allows developers to explore, experiment, and work on various projects with the assurance that their primary system remains secure and unaffected.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resource efficiency
&lt;/h3&gt;

&lt;p&gt;When we compare Docker to traditional virtual machines (VMs), Docker's superior resource efficiency becomes evident. This difference primarily stems from Docker's architecture, which contrasts starkly with that of VMs. Docker containers share the host system's kernel and only require the application and its dependencies to operate. In contrast, VMs need a full operating system to function. This architectural distinction makes Docker containers inherently less resource-intensive, allowing for more agile and responsive environments that are well-suited to modern software development needs.&lt;/p&gt;

&lt;p&gt;Docker's lightweight nature is one of its key advantages. Containers require significantly less disk space and memory than VMs, leading to faster deployment and startup times. This quick start-up is especially beneficial in development processes, where time efficiency is critical.&lt;/p&gt;

&lt;p&gt;In terms of resource consumption, Docker also has the upper hand. VMs typically allocate fixed resources to each instance, which can be excessive and lead to inefficient resource use. Docker's dynamic resource allocation ensures that containers use only what is necessary, optimizing system resource utilization and enabling the concurrent running of more applications.&lt;/p&gt;

&lt;p&gt;Furthermore, Docker simplifies maintenance compared to VMs. A VM is an entire operating system that necessitates regular updates and management, whereas Docker containers, encapsulating only the necessary application components, are easier to manage and update. This simplicity extends to security patches and configuration management.&lt;/p&gt;

&lt;p&gt;The most notable advantage, perhaps, is the reduced overhead of Docker containers. By forgoing the need to run a full guest operating system, Docker facilitates better hardware utilization. This efficiency is crucial in environments where resource constraints are a concern, allowing for more applications to be run on the same hardware.&lt;/p&gt;

&lt;p&gt;In summary, Docker's containerization approach significantly lessens the strain on computing resources. It provides isolated, efficient, and manageable environments, making it an ideal tool for contemporary development practices that require agility and the ability to quickly adapt to new requirements. Docker's responsive and efficient environment enables developers to focus on innovation and development, unburdened by the complexities of managing weighty and cumbersome VMs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consistency, Portability, Version Control, and Update Management
&lt;/h3&gt;

&lt;p&gt;One of the key strengths of using Dockerized environments, especially for development purposes, lies in the consistency and portability it offers across different machines. This aspect is crucial for development teams and individual developers who need to ensure that their applications behave the same way, irrespective of where they are being run. &lt;/p&gt;

&lt;p&gt;Docker containers encapsulate not just the application but also its environment. This means that everything needed to run the application - from the operating system, libraries, and dependencies - is packaged together. This packaging ensures that the application runs in the same environment, regardless of the host system. Whether it's being developed on a local machine in Ubuntu or tested on a remote server running CentOS, the application's behavior remains consistent. This consistency eliminates the "it works on my machine" problem, a common challenge in software development.&lt;/p&gt;

&lt;p&gt;The containerized approach of Docker also enhances portability. Containers can be easily moved from one environment to another—be it from a local development machine to a test server, or from a staging environment to production. This portability is particularly beneficial for quickly deploying applications or scaling them across different environments or cloud providers.&lt;/p&gt;

&lt;p&gt;The practice of version-controlling Dockerfiles and associated scripts (like setup and teardown scripts) plays a pivotal role in maintaining the integrity and history of development environments. By keeping these files in a version control system, teams can track changes over time, easily roll back to previous versions if necessary, and maintain a historical record of how environments have evolved. This practice is particularly useful when parts of the toolchain are updated or when introducing new dependencies. &lt;/p&gt;

&lt;p&gt;Having version-controlled Dockerfiles and scripts also simplifies the process of replicating environments. New team members or collaborators can quickly set up their development environments by pulling the latest versions of these files from the repository, ensuring they're working with the most up-to-date configurations. &lt;/p&gt;

&lt;p&gt;Furthermore, the ability to version control these environment configurations aids in update management. When a new version of a tool or library is released, it can be tested in isolation, and the changes can be committed only once they are verified to work as expected. This approach minimizes disruptions and ensures that updates are systematically managed.&lt;/p&gt;

&lt;p&gt;In conclusion, Docker's ability to provide consistent, portable, and easily replicable environments, combined with the best practices of version controlling Dockerfiles and scripts, makes it an invaluable tool in modern software development. It not only streamlines the development process but also enhances collaboration and reduces the risks associated with environment inconsistencies and updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Educational tool
&lt;/h3&gt;

&lt;p&gt;Dockerized environments, particularly when integrated with tools like Visual Studio Code (VSCode), serve as an exceptional educational tool, offering a myriad of benefits for both teaching and learning in the realm of software development. The adoption of Docker in educational settings aligns seamlessly with the growing emphasis on hands-on, practical experience in learning.&lt;/p&gt;

&lt;p&gt;The foremost advantage of Docker in an educational context is the creation of a consistent learning environment. This consistency ensures that all students, regardless of their individual hardware or software configurations, have access to the same development setup. Such uniformity is vital in educational settings to avoid discrepancies that can lead to confusion and hinder the learning process.&lt;/p&gt;

&lt;p&gt;Moreover, Docker significantly eases the setup of development environments. Educators can distribute pre-configured Docker images or Dockerfiles, enabling students to swiftly and effortlessly establish their development environment. This streamlined setup is especially beneficial in time-constrained educational scenarios like workshops or short courses.&lt;/p&gt;

&lt;p&gt;A key aspect of learning with Docker is the provision of a safe, sandboxed space for experimentation. Students can freely experiment with code and various technologies within the confines of Docker containers, without the risk of causing issues in their host system. This safety aspect encourages exploration and learning through experimentation, fostering an environment where trial and error become an integral part of the educational journey.&lt;/p&gt;

&lt;p&gt;In addition to facilitating individual learning, Docker’s replicability and scalability are invaluable assets in classroom settings. The ability to deploy the same environment across numerous machines ensures that Docker-based learning can be scaled to accommodate a large number of students, a feature particularly useful in institutional settings.&lt;/p&gt;

&lt;p&gt;Resource efficiency is another critical benefit of Docker in education. Its lightweight nature, compared to traditional virtual machines, makes Docker a practical choice for educational institutions that may have limited hardware resources. This efficiency ensures that Docker can be widely adopted without significant hardware investments.&lt;/p&gt;

&lt;p&gt;Importantly, learning in Dockerized environments equips students with real-world skills that are highly sought after in the current job market. The practical experience gained with Docker and containerization prepares students for professional roles in software development, bridging the gap between academic learning and industry requirements.&lt;/p&gt;

&lt;p&gt;Lastly, the integration of Docker with version control systems in educational projects promotes collaboration and teaches essential skills for modern software development. Students learn about managing collaborative projects and version-controlling Dockerfiles, skills that are indispensable in professional software development teams.&lt;/p&gt;

&lt;p&gt;In essence, Docker's adaptability and relevance to industry practices make it an invaluable educational tool, providing a platform that supports both the learning of programming and development concepts and the preparation for the technological demands of the professional world.&lt;/p&gt;

&lt;h3&gt;
  
  
  You Almost Convinced Me, But I Don't Have Linux on My Machine
&lt;/h3&gt;

&lt;p&gt;If the idea of Dockerized VSCode environments appeals to you but the absence of Linux on your machine seems like a barrier, there's a viable workaround. This involves using a virtual machine to run a Linux distribution, such as Ubuntu, on your current operating system, whether it's Windows or macOS.&lt;/p&gt;

&lt;p&gt;The first step in this process is to install VirtualBox, a popular virtualization software. VirtualBox allows you to create a virtual environment on your existing system where you can install and run a different operating system. The process of installing VirtualBox is quite straightforward, with plenty of available tutorials to guide you through the installation.&lt;/p&gt;

&lt;p&gt;Once you have VirtualBox installed, the next step is setting up Ubuntu as a virtual machine. This typically involves downloading the Ubuntu ISO file and using it to create a new VM in VirtualBox. The internet is replete with step-by-step guides that walk you through installing Ubuntu on VirtualBox, making it an achievable task even for those new to virtualization.&lt;/p&gt;

&lt;p&gt;After successfully installing Ubuntu on your VM, ensure you perform a system update and install Docker and Git. These installations are crucial as they lay the groundwork for setting up the Dockerized VSCode environment. With Docker and Git installed, you can then proceed to follow the instructions provided in this article to create your Dockerized development environment.&lt;/p&gt;

&lt;p&gt;One of the great advantages of this approach is that, despite using a VM, you can still benefit from multiple, isolated development environments. Each Docker container within your Ubuntu VM can be configured as a separate development space, complete with its own tools, settings, and dependencies. This means within a single VM, you can simultaneously run multiple development environments tailored for different projects or programming languages.&lt;/p&gt;

&lt;p&gt;In essence, this method opens up the possibility of leveraging the benefits of Dockerized VSCode environments, even for those who don't have a Linux-based system. It's a practical solution that extends the power and versatility of Dockerized environments to a wider audience, ensuring that more developers can optimize their workflows and embrace a more efficient development process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related Projects
&lt;/h2&gt;

&lt;p&gt;After searching antoher Dockerized VSCode environments browsing internet, several related projects offer various approaches and configurations that could be an alternative to the aproach described in this article:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;colebrumley/docker-vscode&lt;/strong&gt;: Tailored for macOS users, this project provides a Docker container specifically for VSCode. It focuses on a basic setup of VSCode within Docker, making it a straightforward option for those using macOS. &lt;a href="https://github.com/colebrumley/docker-vscode" rel="noopener noreferrer"&gt;GitHub Link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;beatthat/vscodify-docker&lt;/strong&gt;: This project aims to add a VSCode development environment to any Docker base image. Its flexibility allows integration with a range of Docker base images, offering a generalized solution adaptable to various use cases. &lt;a href="https://github.com/beatthat/vscodify-docker" rel="noopener noreferrer"&gt;GitHub Link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;allamand/docker-vscode&lt;/strong&gt;: Designed for developers working with Go, this project integrates Go and VSCode in a Docker environment. It's a more focused solution for those specifically developing in Go. &lt;a href="https://github.com/allamand/docker-vscode" rel="noopener noreferrer"&gt;GitHub Link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;cmiles74/docker-vscode&lt;/strong&gt;: Offering a comprehensive development environment, this project includes VSCode along with tools like Dotnet CLI, NPM, and Emacs. It's ideal for developers needing a broad set of resources in their Dockerized VSCode setup. &lt;a href="https://github.com/cmiles74/docker-vscode" rel="noopener noreferrer"&gt;GitHub Link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Each of these projects presents a unique take on Dockerizing VSCode, ranging from minimal setups to comprehensive environments with multiple tools, highlighting the versatility and adaptability of Docker in development settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Dockerized VSCode Environments: A Detailed Guide
&lt;/h2&gt;

&lt;p&gt;In this chapter, we delve into the practical aspects of setting up your Dockerized Visual Studio Code environment. This step-by-step guide will walk you through the process using Dockerfile configurations and scripts from the GitHub repository, complete with code snippets and explanations. The focus will be on understanding the Dockerfile content and the &lt;code&gt;run.sh&lt;/code&gt; script, which are crucial to deploying the VSCode environment within Docker.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Explaining the Dockerfile: We'll break down the Dockerfile line by line. This includes understanding the base image selection, the installation of dependencies, the addition of the Microsoft repository for VSCode, and the creation of a non-root user. Each step will be explained to provide insight into why these elements are essential for a stable and functional Dockerized VSCode environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understanding the &lt;code&gt;run.sh&lt;/code&gt; Script: The &lt;code&gt;run.sh&lt;/code&gt; script is key to initiating and running the Dockerized VSCode. We will explore the script's functionality, including setting up X11 forwarding for GUI support, configuring Docker run commands, and mounting necessary volumes. This explanation will help you understand how the script interacts with the Docker environment to launch VSCode.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Code Snippets and Execution: Actual code snippets from the Dockerfile and &lt;code&gt;run.sh&lt;/code&gt; script will be presented. These snippets will be accompanied by instructions on how to execute them, ensuring you can follow along and implement the setup in your own environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Customization Tips: Additional tips on how to customize the Dockerfile and the script for various development needs will be provided. This will enable you to tailor the Dockerized VSCode environment to fit your specific project requirements.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Explaining the Dockerfile
&lt;/h3&gt;

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

&lt;span class="c"&gt;# Use Ubuntu Jammy as the base image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:jammy-20240111&lt;/span&gt;

&lt;span class="c"&gt;# Update package list and install dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    wget &lt;span class="se"&gt;\
&lt;/span&gt;    gnupg &lt;span class="se"&gt;\
&lt;/span&gt;    software-properties-common &lt;span class="se"&gt;\
&lt;/span&gt;    apt-transport-https &lt;span class="se"&gt;\
&lt;/span&gt;    git &lt;span class="se"&gt;\
&lt;/span&gt;    iputils-ping &lt;span class="se"&gt;\
&lt;/span&gt;    iproute2 &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="c"&gt;# Add the Microsoft repository for VSCode&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;wget &lt;span class="nt"&gt;-qO-&lt;/span&gt; https://packages.microsoft.com/keys/microsoft.asc | gpg &lt;span class="nt"&gt;--dearmor&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; packages.microsoft.gpg &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; root &lt;span class="nt"&gt;-g&lt;/span&gt; root &lt;span class="nt"&gt;-m&lt;/span&gt; 644 packages.microsoft.gpg /usr/share/keyrings/ &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb [arch=amd64 signed-by=/usr/share/keyrings/packages.microsoft.gpg] https://packages.microsoft.com/repos/code stable main"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /etc/apt/sources.list.d/vscode.list

&lt;span class="c"&gt;# Install Visual Studio Code&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; code

&lt;span class="c"&gt;# Create a non-root user&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;-m&lt;/span&gt; vscodeuser
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; vscodeuser&lt;/span&gt;

&lt;span class="c"&gt;# The command to run VSCode&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["code", "--no-sandbox", "--wait", "--verbose"]&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;The Dockerfile starts by specifying Ubuntu Jammy (version 22.04 as of 2024) as the base image. This choice is due to Ubuntu's stability and popularity, making it an ideal choice for a consistent development environment.&lt;/p&gt;

&lt;p&gt;The next steps involve updating the package list and installing essential dependencies. These include tools like &lt;code&gt;wget&lt;/code&gt; for downloading files, &lt;code&gt;gnupg&lt;/code&gt; for encryption, &lt;code&gt;git&lt;/code&gt; for version control, &lt;code&gt;iputils-ping&lt;/code&gt; and &lt;code&gt;iproute2&lt;/code&gt; for being able to execute some network related commands in visual studio console like &lt;code&gt;ping&lt;/code&gt; or &lt;code&gt;ip address&lt;/code&gt;, among others. This setup ensures that all necessary tools I considered are available in the Docker environment.&lt;/p&gt;

&lt;p&gt;To install VSCode, the Dockerfile adds the Microsoft repository. This is done by downloading Microsoft's GPG keys, ensuring the authenticity of the packages, and then adding the VSCode repository to the sources list. With the repository in place, the Dockerfile proceeds to update the package list again and installs VSCode. This ensures that the latest version of VSCode when generating the image is installed in the Docker container.&lt;/p&gt;

&lt;p&gt;The Dockerfile also takes care of creating a non-root user, &lt;code&gt;vscodeuser&lt;/code&gt;. Running applications as a non-root user in Docker containers is a good practice for security. This user will be related to the user that runs the script on the next section (more on this later).&lt;/p&gt;

&lt;p&gt;Finally, the Dockerfile specifies the command to run VSCode (&lt;code&gt;code&lt;/code&gt;) with certain flags for compatibility and verbose logging. We will run docker with -d flag so logging will not be visible when running docker, but to access logs, docker logs command will be needed to run whilst the container is running. I was not able to run vscode without adding  &lt;code&gt;--no-sandbox&lt;/code&gt;, but I do not think this is important for this case as we are already controlling how vscode will be sandboxed. Finally, &lt;code&gt;--wait&lt;/code&gt; was also needed, because otherwise the container would be killed as soon as vscode is launched.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the &lt;code&gt;run.sh&lt;/code&gt; Script
&lt;/h2&gt;

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

&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="nv"&gt;XAUTH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;XAUTHORITY&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/.Xauthority&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;DOCKER_XAUTHORITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;XAUTH&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;.docker
&lt;span class="nb"&gt;cp&lt;/span&gt; &lt;span class="nt"&gt;--preserve&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;all &lt;span class="nv"&gt;$XAUTH&lt;/span&gt; &lt;span class="nv"&gt;$DOCKER_XAUTHORITY&lt;/span&gt;
xauth nlist &lt;span class="nv"&gt;$DISPLAY&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s1"&gt;'s/^..../ffff/'&lt;/span&gt; | xauth &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nv"&gt;$DOCKER_XAUTHORITY&lt;/span&gt; nmerge -

docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--name&lt;/span&gt; vscode-base-1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; /etc/passwd:/etc/passwd:ro &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;DISPLAY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;unix&lt;span class="nv"&gt;$DISPLAY&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;NO_AT_BRIDGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;GTK_THEME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Adwaita &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; /tmp/.X11-unix:/tmp/.X11-unix:ro &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;XAUTHORITY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$DOCKER_XAUTHORITY&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nv"&gt;$DOCKER_XAUTHORITY&lt;/span&gt;:&lt;span class="nv"&gt;$DOCKER_XAUTHORITY&lt;/span&gt;:ro &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; ./home:/home/vscodeuser &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; ./Documents:/home/vscodeuser/Documents &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; ./home:/home/&lt;span class="nv"&gt;$USER&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-v&lt;/span&gt; ./Documents:/home/&lt;span class="nv"&gt;$USER&lt;/span&gt;/Documents &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;HOME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/home/vscodeuser &lt;span class="se"&gt;\&lt;/span&gt;
    inigoetxaniz/vscode-base:latest 


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;run.sh&lt;/code&gt; script is crucial for launching the Dockerized VSCode environment. It handles several important tasks that are not so habitual when working with docker.&lt;/p&gt;

&lt;p&gt;Perhaps, one of the most unused features of docker is forwarding X11 for GUI support. X11 is a protocol for remote graphical interfaces. It's commonly used to display GUI applications running on a server onto a client machine. In the context of Docker, X11 forwarding enables GUI applications running inside a Docker container, like VSCode, to display on the host machine's screen. The script sets up X11 forwarding by first determining the X11 authentication file location and then copying this information into a new file (DOCKER_XAUTHORITY). This step ensures that the Docker container has the necessary permissions to display its GUI on the host's screen.&lt;/p&gt;

&lt;p&gt;Later, the docker run command includes several options to facilitate X11 forwarding. &lt;code&gt;-e DISPLAY=unix$DISPLAY&lt;/code&gt; sets the DISPLAY environment variable inside the container, pointing it to the host's display. &lt;code&gt;-v /tmp/.X11-unix:/tmp/.X11-unix:ro&lt;/code&gt; mounts the X11 Unix socket from the host into the container, allowing the container to communicate with the host's X server. &lt;code&gt;-e XAUTHORITY=$DOCKER_XAUTHORITY&lt;/code&gt; and the associated volumen mount &lt;code&gt;-v $DOCKER_XAUTHORITY:$DOCKER_XAUTHORITY:ro&lt;/code&gt; pass the authentication details to the container. This setup works well in an Ubuntu environment, but it's important to note that X11 forwarding configurations may vary based on the host's operating system and Docker version.&lt;/p&gt;

&lt;p&gt;While X11 forwarding in Docker is an effective way to display GUI applications like VSCode from a container to the host screen, it's important to consider security implications. X11 forwarding allows the container to interact with the host's X server, which could potentially be a security concern. However, in the context of running a trusted application like VSCode, this setup does not introduce significant additional risks compared to running VSCode directly on the host.&lt;/p&gt;

&lt;p&gt;When using X11 forwarding to run VSCode in Docker, the security risk is comparable to running it natively on your system. The isolation provided by Docker still offers a layer of protection, as the activities within the container remain separate from the host system. This means that while the container can display its output on the host, it doesn't have unrestricted access to the host system.&lt;/p&gt;

&lt;p&gt;In essence, using X11 forwarding for trusted applications like VSCode in Docker strikes a balance between functionality and security. It allows for the convenience and benefits of Dockerized environments without adding significant security threats, especially when used in trusted and controlled development scenarios.&lt;/p&gt;

&lt;p&gt;In this case &lt;code&gt;vscode-base-1&lt;/code&gt; is the name of the container. &lt;code&gt;--rm&lt;/code&gt; and &lt;code&gt;-d&lt;/code&gt; options make docker container to be deleted after vscode is exited and also run in a detached mode so that nothing is shown in the console and application returns to the user. Logs are still available running in the console &lt;code&gt;docker logs vscode-base-1&lt;/code&gt;. &lt;code&gt;-v ./home:/home/vscodeuser&lt;/code&gt; sandboxes all home related files to &lt;code&gt;./home&lt;/code&gt;, which allows us to store configuration options, extensions installed during ussage of vscode and other things we could install during the use. &lt;code&gt;-u $(id -u):$(id -g)&lt;/code&gt; sets running user as current user in the host. &lt;code&gt;-v ./Documents:/home/vscodeuser/Documents&lt;/code&gt; allows us to control which content is accessible from vscode and this is where I propose to store your working project files. Finally, &lt;code&gt;-e HOME=/home/vscodeuser&lt;/code&gt; sets &lt;code&gt;/home/vscodeuser&lt;/code&gt; as home folder independently of the current user name that is launching vscode from docker. I also added &lt;code&gt;-v ./home:/home/$USER&lt;/code&gt; and &lt;code&gt;-v ./Documents:/home/$USER/Documents&lt;/code&gt;, because in some cases docker container was refering to the user name that launched docker container. Now both &lt;code&gt;/home/vscodeuser&lt;/code&gt; and &lt;code&gt;/home/$USER&lt;/code&gt; point to the same location solving this issue.&lt;/p&gt;

&lt;p&gt;This guide to setting up a Dockerized VSCode environment, particularly the &lt;code&gt;run.sh&lt;/code&gt; script, exemplifies the balance between sophisticated functionality and user-friendliness. The script simplifies complex processes like X11 forwarding, making it accessible even to those who might be new to Docker or Linux environments. By automating intricate setup steps and providing clear explanations for each part, it significantly eases the user's journey in creating a secure, isolated, and efficient development workspace. This approach not only caters to advanced users seeking customization but also to beginners desiring a straightforward path to leveraging Docker for their development needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases and Customization
&lt;/h2&gt;

&lt;p&gt;This section introduces two practical use cases, illustrating how you can tailor Dockerized VSCode environments for specific development needs. The first example focuses on creating an environment for Go language development, while the second caters to developing VSCode extensions with Node.js and NPM. These examples are not exhaustive but serve as a starting point for customization.&lt;/p&gt;

&lt;p&gt;Both Dockerfiles begin with the inigoetxaniz/vscode-base image, ensuring a consistent foundation. Customizations involve switching to the root user to install necessary packages specific to each environment — Go for the first and Node.js for the second — and then reverting back to the non-root vscodeuser. This approach maintains security while allowing for necessary installations.&lt;/p&gt;

&lt;p&gt;Environment variables are set up as needed, particularly for the Go development environment, to ensure the correct configuration of the workspace. The run.sh scripts for these environments are similar to the one detailed earlier, underscoring the ease of adapting the base setup to various requirements.&lt;/p&gt;

&lt;p&gt;These Dockerfiles demonstrate the flexibility and adaptability of Dockerized environments, providing a blueprint for developers to create their customized setups. Whether it's for a specific programming language or a particular type of development work, these examples show how Docker can be effectively used to create efficient and tailored development environments.&lt;/p&gt;

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

&lt;span class="c"&gt;# Start from the base image you created for VSCode&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; inigoetxaniz/vscode-base:latest&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; root&lt;/span&gt;

&lt;span class="c"&gt;# Download and Install Go&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;wget https://go.dev/dl/go1.21.6.linux-amd64.tar.gz &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-C&lt;/span&gt; /usr/local &lt;span class="nt"&gt;-xzf&lt;/span&gt; go1.21.6.linux-amd64.tar.gz &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm &lt;/span&gt;go1.21.6.linux-amd64.tar.gz

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; vscodeuser&lt;/span&gt;

&lt;span class="c"&gt;# Set up the Go environment&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; GOPATH /home/vscodeuser/go&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; PATH $GOPATH/bin:/usr/local/go/bin:$PATH&lt;/span&gt;

&lt;span class="c"&gt;# The command to run VSCode&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["code", "--no-sandbox", "--wait", "--verbose"]&lt;/span&gt;


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

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

&lt;span class="c"&gt;# Start from the base image you created for VSCode&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; inigoetxaniz/vscode-base&lt;/span&gt;

&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; root&lt;/span&gt;

&lt;span class="c"&gt;# Download and install the latest LTS version of Node.js&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    wget https://nodejs.org/dist/v20.11.0/node-v20.11.0-linux-x64.tar.xz &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xJf&lt;/span&gt; node-v20.11.0-linux-x64.tar.xz &lt;span class="nt"&gt;-C&lt;/span&gt; /usr/local &lt;span class="nt"&gt;--strip-components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nb"&gt;rm &lt;/span&gt;node-v20.11.0-linux-x64.tar.xz

&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; yo generator-code

&lt;span class="c"&gt;# Switch back to the non-root user&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; vscodeuser&lt;/span&gt;

&lt;span class="c"&gt;# The command to run VSCode&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["code", "--no-sandbox", "--wait", "--verbose"]&lt;/span&gt;


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

&lt;/div&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%2Foqbm34yk5rxi30kix4ya.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%2Foqbm34yk5rxi30kix4ya.png" alt="Two different instances of vscode in same machine"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;In this guide, we've explored the versatile and secure world of Dockerized VSCode environments. Key highlights include the use of Docker for creating isolated, customizable, and resource-efficient development spaces, enhancing both security and consistency across various machines. We've dissected the Dockerfile to understand its structure and purpose and delved into the &lt;code&gt;run.sh&lt;/code&gt; script, particularly focusing on X11 forwarding for GUI support in Docker. We've also covered practical use cases, demonstrating how to tailor Dockerized environments for specific development needs like Go and Node.js. This guide not only provides a step-by-step process for setting up these environments but also emphasizes their adaptability and ease of use, making Dockerized VSCode a valuable tool for developers seeking an efficient and secure development workflow.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>vscode</category>
      <category>devops</category>
    </item>
    <item>
      <title>Streamlining Home Entertainment: How to Use a Linux Machine for Streaming Content to Smart TVs and More</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Sat, 06 Jan 2024 16:09:10 +0000</pubDate>
      <link>https://dev.to/ietxaniz/streamlining-home-entertainment-how-to-use-a-linux-machine-for-streaming-content-to-smart-tvs-and-more-dgg</link>
      <guid>https://dev.to/ietxaniz/streamlining-home-entertainment-how-to-use-a-linux-machine-for-streaming-content-to-smart-tvs-and-more-dgg</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Hey there! Ever thought about turning your old laptop or a Raspberry Pi into a personal streaming powerhouse? You're not alone. Many of us find the idea of ditching the limitations of traditional smart TV platforms (think annoying ads, blocked content, and less-than-stellar USB playback) pretty appealing.&lt;/p&gt;

&lt;p&gt;In this guide, I'll walk you through a slightly intricate but rewarding journey to set up your own streaming service. This might be a bit of a lengthy read, but stick with me. By the end, you’ll be able to stream content directly from your laptop to your TV, bypassing those smart TV nuances and enjoying your media just the way you like it.&lt;/p&gt;

&lt;p&gt;Let’s dive in and transform the way you experience home entertainment!&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of the Setup
&lt;/h2&gt;

&lt;p&gt;We start by adding a new sound interface. This solution eliminates the distraction of audio playing in the speakers of the laptop, channeling all sound directly to OBS for a seamless streaming experience. Then, we install Docker, establishing isolated environments for some of the services of our system. This isolation ensures operational efficiency and prevents interference with other processes on the machine. Next, OBS takes the center stage, adeptly capturing and transmitting both audio and video. It's the key player that brings your content to life, offering user-friendly customization for an optimized streaming setup. Finally, Nginx acts as a versatile powerhouse, adeptly juggling two critical roles. It not only serves as a reverse proxy for OBS, managing the live video streams, but also doubles as a web server. This dual functionality enables Nginx to host the webpage through which your content is accessed, completing the circle of our streaming service. Together, these components interlink and work in harmony, creating a robust and versatile home streaming solution.&lt;/p&gt;

&lt;p&gt;In the following sections, we’ll delve deeper into each component, explaining the setup process. Get ready to transform your old laptop or Raspberry Pi into a streaming powerhouse!&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements and Preparations
&lt;/h2&gt;

&lt;p&gt;Fine-tuning our setup to match the specific environment of an old laptop, we're demonstrating that high-end hardware isn't a necessity for a functional home streaming service. The chosen machine is a modest Intel i3 with 4GB of RAM, illustrating that even older computers can effectively handle streaming tasks. This setup runs on Ubuntu, a user-friendly operating system that's ideal for such projects. While this guide primarily focuses on Ubuntu, users with different Linux distributions can still follow along, though they might encounter slight variations in the setup process.&lt;/p&gt;

&lt;p&gt;Before diving into the streaming setup, updating your Ubuntu system is crucial. Start by opening a terminal; you can usually do this by searching for 'Terminal' in your system's applications menu or by using the shortcut &lt;code&gt;Ctrl + Alt + T&lt;/code&gt;. In the terminal, run the following commands to update your system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt upgrade
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This process ensures your system is secure and functions smoothly, paving the way for a successful setup. As we proceed, basic command line familiarity will be beneficial, but don't worry—I'll provide all the necessary commands, making it easy to follow along. We'll be configuring an external sound interface to optimize audio output for OBS and installing Docker to run Nginx in a container. This approach keeps our setup clean and modular. Embrace this project with patience and a willingness to learn; it's an exciting journey into the realm of home streaming. With these preparations, we're ready to start building our streaming system, beginning with the new sound interface installation. Let's get started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a New Sound Interface
&lt;/h2&gt;

&lt;p&gt;Enhancing your streaming setup begins with the addition of a virtual sound interface, a key move for a clean audio experience. This step-by-step guide will help you create a virtual audio streamer on your Linux system, perfect for directing audio to OBS and keeping your laptop's speakers silent.&lt;/p&gt;

&lt;p&gt;First, we need to check if PulseAudio, a powerful sound server, is already installed on your machine. Open your terminal and enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;pulseaudio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After confirming PulseAudio's installation, the next move is to modify its configuration to add a new virtual sound interface. Using a text editor like Nano, open the PulseAudio configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/pulse/default.pa
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scroll to the end of the file and add the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;load-module module-null-sink sink_name=VirtualSink sink_properties=device.description=Virtual_Audio_Streamer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command instructs PulseAudio to create a new virtual audio output named 'VirtualSink' with the description 'Virtual_Audio_Streamer'. Save the changes and exit the editor. For these changes to take effect, a system restart is necessary.&lt;/p&gt;

&lt;p&gt;Once your system is back up, navigate to your sound settings, accessible through the system settings or control panel. In the output section, you will now find 'Virtual_Audio_Streamer' alongside other audio interfaces. Set it as the default output device.&lt;/p&gt;

&lt;p&gt;By setting 'Virtual_Audio_Streamer' as the default, the system audio is routed to this virtual sink, meaning you won't hear any sound from your laptop's speakers. Instead, all audio is directed to this virtual interface, ready for OBS to capture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Docker
&lt;/h2&gt;

&lt;p&gt;Setting up docker on Linux is a straighforward process if you follow the official documentation. If your linux distro is ubuntu you can use the next link &lt;a href="https://docs.docker.com/engine/install/ubuntu/"&gt;Docker's official installation guide ubuntu&lt;/a&gt; and if it is debian or raspberry pi 64 bit, you can use the next link &lt;a href="https://docs.docker.com/engine/install/debian/"&gt;Docker's official installation guide ubuntu&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I install following the instructions in &lt;strong&gt;Install using the apt repository&lt;/strong&gt; section. I never had any issues with this method and its quite simple.&lt;/p&gt;

&lt;p&gt;I find important to follow &lt;strong&gt;post-installation steps&lt;/strong&gt; just after finishing instalation. This includes adding your user to the Docker group to avoid needing to use &lt;code&gt;sudo&lt;/code&gt; for every Docker command. Execute the following commands in your terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;groupadd docker
&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; docker &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands create a new group named 'docker' and add your user to this group. To apply these changes, restart your system. This ensures that your user permissions are updated correctly.&lt;/p&gt;

&lt;p&gt;After restarting, you should verify the installation, check if Docker and Docker Compose are correctly installed by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker version
docker compose version
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These commands will display the version of Docker and Docker compose installed on your system, confirming that the installation was successful.&lt;/p&gt;

&lt;p&gt;By following these steps, you'll have Docker up and running on your system. Docker is an extremely powerful tool for containerization, allowing you to run applications in isolated environments. This will be especially useful for our streaming service setup, where Docker will manage the Nginx server in a container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing OBS Studio on Ubuntu
&lt;/h2&gt;

&lt;p&gt;Installing OBS Studio on your Ubuntu/Debian system is a straightforward process, perfect for beginners, and involves using Ubuntu's or Debian's PPA to ensure easy installation and updates. Type the following command in the terminal to add the OBS Studio PPA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo add-apt-repository ppa:obsproject/obs-studio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step connects your system to the OBS Studio repository. After adding the PPA, update your system's package list and install &lt;strong&gt;OBS studio&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update
sudo apt install obs-studio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing OBS Studio, hold off on launching it right away. We need to set up Nginx first, as it's a crucial part of our streaming setup. Once Nginx is up and running, we'll circle back to OBS Studio to configure it for streaming. This ensures a smooth integration between your streaming software and the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Web Interface for Streaming
&lt;/h2&gt;

&lt;p&gt;In this part of our setup, we'll create a web interface for the streaming service using Docker and Nginx. This will involve setting up a directory structure and configuring files.&lt;/p&gt;

&lt;p&gt;I will not explain how every item works. Docker compose file is quite simple and straightforward, but nginx configuration file was quite tricky as I did not have any previous experience with rtmp and I had to make many different tries till I got a working solution. Web page is also very simple, I did not dedicate much time to this one, I just add a html page with a video player. I did play with other two or three different video players and this one from &lt;a href="https://github.com/videojs/video.js"&gt;https://github.com/videojs/video.js&lt;/a&gt;, is the one that I liked most and just works fine.&lt;/p&gt;

&lt;p&gt;First we need to create a directory for the project. I will use ~/stream-service in my setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; ~/stream-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will create three directories: ./conf for nginx configuration file, ./hls for the streaming content that will be generated by obs and ./web for hosting index.html file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/stream-service
&lt;span class="nb"&gt;mkdir &lt;/span&gt;conf hls web
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also add in project root folder a docker compose file. This will launch nginx service and redirect container ports to host ports. We will also add a &lt;strong&gt;restart: always&lt;/strong&gt; line so that the service is started automatically when we switch on the laptop. So, create a file called ~/stream-service/docker-compose.yml with the next content:&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;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tiangolo/nginx-rtmp:latest-2023-10-16&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;obs-nginx&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1935:1935"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./conf/obs.conf:/etc/nginx/nginx.conf&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./hls:/mnt/hls&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./web:/web&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create also the file ~/stream-service/conf/obs.conf file with the next content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;worker_processes&lt;/span&gt; &lt;span class="s"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;rtmp_auto_push&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;events&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;rtmp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;1935&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;application&lt;/span&gt; &lt;span class="s"&gt;live&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kn"&gt;live&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kn"&gt;record&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kn"&gt;hls&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kn"&gt;hls_path&lt;/span&gt; &lt;span class="n"&gt;/mnt/hls&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kn"&gt;hls_fragment&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kn"&gt;hls_playlist_length&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;http&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;sendfile&lt;/span&gt; &lt;span class="no"&gt;off&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;tcp_nopush&lt;/span&gt; &lt;span class="no"&gt;on&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;# aio on;&lt;/span&gt;
    &lt;span class="kn"&gt;directio&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;default_type&lt;/span&gt; &lt;span class="nc"&gt;application/octet-stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kn"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;# Disable cache&lt;/span&gt;
            &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Cache-Control'&lt;/span&gt; &lt;span class="s"&gt;'no-cache'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;# CORS setup&lt;/span&gt;
            &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Allow-Origin'&lt;/span&gt; &lt;span class="s"&gt;'*'&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Expose-Headers'&lt;/span&gt; &lt;span class="s"&gt;'Content-Length'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;# allow CORS preflight requests&lt;/span&gt;
            &lt;span class="kn"&gt;if&lt;/span&gt; &lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request_method&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'OPTIONS')&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Allow-Origin'&lt;/span&gt; &lt;span class="s"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Max-Age'&lt;/span&gt; &lt;span class="mi"&gt;1728000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Content-Type'&lt;/span&gt; &lt;span class="s"&gt;'text/plain&lt;/span&gt; &lt;span class="s"&gt;charset=UTF-8'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kn"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Content-Length'&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kn"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;204&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="kn"&gt;types&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kn"&gt;text/html&lt;/span&gt; &lt;span class="s"&gt;html&lt;/span&gt; &lt;span class="s"&gt;htm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kn"&gt;application/dash+xml&lt;/span&gt; &lt;span class="s"&gt;mpd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kn"&gt;application/vnd.apple.mpegurl&lt;/span&gt; &lt;span class="s"&gt;m3u8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="kn"&gt;video/mp2t&lt;/span&gt; &lt;span class="s"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="kn"&gt;index&lt;/span&gt; &lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="kn"&gt;root&lt;/span&gt; &lt;span class="n"&gt;/mnt/hls&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/index.html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kn"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;/web/index.html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly create the ~/stream-service/web/index.html file with the next content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Live Stream&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://vjs.zencdn.net/7.8.4/video-js.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;video&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"my-video"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"video-js"&lt;/span&gt; &lt;span class="na"&gt;controls&lt;/span&gt; &lt;span class="na"&gt;preload=&lt;/span&gt;&lt;span class="s"&gt;"auto"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"640"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"360"&lt;/span&gt; &lt;span class="na"&gt;data-setup=&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;source&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/stream.m3u8"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/x-mpegURL"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"vjs-no-js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        To view this video please enable JavaScript, and consider upgrading to a web browser that
        &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://videojs.com/html5-video-support/"&lt;/span&gt; &lt;span class="na"&gt;target=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;supports HTML5 video&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/video&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://vjs.zencdn.net/7.8.4/video.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, change the web pages file permission. Otherwise nginx will not be able to serve it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 777 ~/stream-server/web/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Launching the services
&lt;/h2&gt;

&lt;p&gt;With configuration files ready, in a terminal execute next instructions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/stream-service
docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second command will take some time. It needs to download nginx image and start the service. Once ready you should see a text similar to &lt;strong&gt;Attaching to obs-nginx&lt;/strong&gt; in the terminal.&lt;/p&gt;

&lt;p&gt;Once everything is up and running, your streaming service will be accessible via the web interface (&lt;code&gt;index.html&lt;/code&gt;). As users visit your webpage, they can view the content streamed through OBS and processed by your Nginx server.&lt;/p&gt;

&lt;p&gt;Before being able to access the web page, you will need to know the ip address of your laptop. This can be obtained with the next instruction in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ip address
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we have docker installed you will see many networks. The network we are seeking it's typically named something like &lt;code&gt;eth0&lt;/code&gt; (for wired connections) or &lt;code&gt;wlp2s0&lt;/code&gt; or &lt;code&gt;wlan0&lt;/code&gt; (for wireless connections int laptop or raspberry pi). In my case it's &lt;code&gt;wlp2s0&lt;/code&gt; with the IP address &lt;code&gt;192.168.1.104&lt;/code&gt;. Now I can access to &lt;code&gt;http://192.168.1.104/index.html&lt;/code&gt;, but the browser will just tell me that &lt;strong&gt;The media could not be found...&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring OBS for Streaming
&lt;/h2&gt;

&lt;p&gt;Finally we need to configure OBS studio. Once we have the rest setup it is quite easy. We start by launching OBS stduio. If it's the first time you're opening OBS, you might see the Auto-Configuration Wizard. You can use this to set up your stream, or you can configure it manually in the settings. I will explain the second method.&lt;/p&gt;

&lt;p&gt;In the OBS main window, find the 'Settings' button, usually located in the lower right corner. Click on it to open the settings window. Once the popup window opens, we select the stream tab (second in the left part of the window). And set the next settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service: Custom
Server: rtmp://localhost/live
Stream Key: stream
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After entering these details, click 'Apply' and then 'OK' to save your streaming settings.&lt;/p&gt;

&lt;p&gt;Now, you need to set up your video and audio sources in OBS. Before doing it you can open a media and start playing it. Afterwards,  click the '+' button under the 'Sources' window and select the media you are playing. OBS automatically captures your primary desktop audio and microphone. You can adjust these and add additional audio sources in the 'Audio Mixer' section. Once your sources are set up, you're ready to go live. Just click the 'Start Streaming' button in OBS. Your content should now be streaming to your Nginx server and accessible through your configured web interface.&lt;/p&gt;

&lt;p&gt;Now you can open in a devices browser the web address configured in the previous section and you should be able to play the media in your other device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;If you encounter issues or the stream isn't accessible on your smart TV, make sure your TV is connected to the same network as your streaming server. Also, check if any firewall or network settings are blocking access to the server. And still, if you're having difficulties or if there's something in this guide that isn't clear, please feel free to post your questions or concerns below. Your feedback is valuable and can help improve this guide. I'll try to provide advice or update the article to address common issues.&lt;/p&gt;

&lt;p&gt;By following this guide, you've taken a big step in enhancing your home entertainment system. This DIY approach not only offers a customized viewing experience but also expands your technical skills. Enjoy your new streaming capability, and happy streaming!&lt;/p&gt;

</description>
      <category>streaming</category>
      <category>docker</category>
      <category>nginx</category>
      <category>obs</category>
    </item>
    <item>
      <title>Go deadlock detection: delock library</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Tue, 05 Dec 2023 14:31:58 +0000</pubDate>
      <link>https://dev.to/ietxaniz/go-deadlock-detection-delock-library-1eig</link>
      <guid>https://dev.to/ietxaniz/go-deadlock-detection-delock-library-1eig</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In the Go programming world, managing concurrency is a part of everyday life. Go makes concurrent programming relatively straightforward with its built-in primitives like goroutines and channels. However, when it comes to locking structures to ensure thread safety, things can get a bit tricky.&lt;/p&gt;

&lt;p&gt;Typically, we use a pointer to a structure and consistently call its methods to maintain thread safety. This approach works well for most scenarios, but complex algorithms demand careful consideration to avoid concurrency issues, especially deadlocks.&lt;/p&gt;

&lt;p&gt;While working on a large-scale project for a caching implementation in an authentication service, I encountered an intriguing problem. Occasionally, and quite rarely, the system would hang. Race conditions were unlikely culprits, as I diligently used mutexes within structures. This left me suspecting deadlocks. But how could I confirm this and, more importantly, identify where they were happening? That's where the idea for &lt;code&gt;delock&lt;/code&gt; began – a tool specifically designed to detect and pinpoint deadlocks in Go applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Deadlocks in Go
&lt;/h2&gt;

&lt;p&gt;Deadlocks in Go, or in any programming language for that matter, are akin to a gridlock in traffic – everything comes to a standstill. A deadlock occurs when two or more goroutines are waiting on each other to release resources, leading to a situation where none of them can proceed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Go Runtime Deadlock Detection
&lt;/h3&gt;

&lt;p&gt;This example, albeit a bit contrived, effectively illustrates a fundamental deadlock scenario. In the &lt;code&gt;Execute&lt;/code&gt; method, we acquire a mutex lock and then call the same method recursively without ever releasing the lock. This leads to an attempt to acquire the lock again while it's still held by the same goroutine, causing a deadlock.&lt;/p&gt;

&lt;p&gt;Though this is a simple and somewhat unrealistic example, it mirrors real-world scenarios where deadlocks occur due to improper lock handling. It’s a classic case of a process indefinitely waiting on itself. The Go runtime is adept at catching such blatant deadlocks in a single-threaded context, where the entire application grinds to a halt. This example serves as a reminder of how subtle mistakes in concurrency management can lead to significant issues, and why it's crucial to code with caution when dealing with locks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;LockExample&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;    &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;LockExample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value: %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="n"&gt;LockExample&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon running the simple deadlock example with standard &lt;code&gt;sync.Mutex&lt;/code&gt;, the Go runtime effectively detects and reports a deadlock. Here's what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The log statement &lt;code&gt;2023/12/05 12:38:02 value: 1&lt;/code&gt; indicates that the &lt;code&gt;Execute&lt;/code&gt; function ran once and incremented &lt;code&gt;Value&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Immediately after, the program crashes with a fatal error: &lt;code&gt;all goroutines are asleep - deadlock!&lt;/code&gt;. This error is thrown by the Go runtime when it detects that all goroutines are waiting on each other, with no possibility of resuming.&lt;/li&gt;
&lt;li&gt;The stack trace provided points to where the deadlock occurs, highlighting the recursive call to &lt;code&gt;Execute&lt;/code&gt; that attempts to reacquire an already held lock.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This result demonstrates the Go runtime's ability to detect simple deadlocks where the entire program is stuck waiting for locks to be released. It serves as a practical example of how easy it is to fall into a deadlock trap and the importance of careful lock management.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run ./examples/simple_std
2023/12/05 12:38:02 value: 1
fatal error: all goroutines are asleep - deadlock!

goroutine 1 &lt;span class="o"&gt;[&lt;/span&gt;sync.Mutex.Lock]:
sync.runtime_SemacquireMutex&lt;span class="o"&gt;(&lt;/span&gt;0x485040?, 0x0?, 0xc00007e050?&lt;span class="o"&gt;)&lt;/span&gt;
        /usr/local/go/src/runtime/sema.go:77 +0x25
sync.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;Mutex&lt;span class="o"&gt;)&lt;/span&gt;.lockSlow&lt;span class="o"&gt;(&lt;/span&gt;0xc0000120e0&lt;span class="o"&gt;)&lt;/span&gt;
        /usr/local/go/src/sync/mutex.go:171 +0x15d
sync.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;Mutex&lt;span class="o"&gt;)&lt;/span&gt;.Lock&lt;span class="o"&gt;(&lt;/span&gt;...&lt;span class="o"&gt;)&lt;/span&gt;
        /usr/local/go/src/sync/mutex.go:90
main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;LockExample&lt;span class="o"&gt;)&lt;/span&gt;.Execute&lt;span class="o"&gt;(&lt;/span&gt;0xc0000120e0&lt;span class="o"&gt;)&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/examples/simple_std/main.go:15 +0x4c
main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;LockExample&lt;span class="o"&gt;)&lt;/span&gt;.Execute&lt;span class="o"&gt;(&lt;/span&gt;0xc0000120e0&lt;span class="o"&gt;)&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/examples/simple_std/main.go:21 +0x12a
main.main&lt;span class="o"&gt;()&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/examples/simple_std/main.go:26 +0x1f
&lt;span class="nb"&gt;exit &lt;/span&gt;status 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Limitations in Complex Scenarios
&lt;/h3&gt;

&lt;p&gt;In real-world programming, especially in services, it's common to have multiple goroutines performing different tasks. In such environments, a deadlock might not stop the entire application, making it more challenging to detect and resolve.&lt;/p&gt;

&lt;p&gt;To illustrate this, let's modify our previous example to fit into a broader context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"sync"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;LockExample&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;    &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;LockExample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&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;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;LockExample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value: %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="n"&gt;LockExample&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="n"&gt;readValueChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;readValueChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;timeoutChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;timeoutChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;

        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;timeoutChan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"waiting..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;readValueChan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value: %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetValue&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this version, we run &lt;code&gt;Execute&lt;/code&gt; in a separate goroutine, simulating a background process in a service. Another goroutine attempts to read the &lt;code&gt;Value&lt;/code&gt; field, while the main routine periodically checks if the value has been read.&lt;/p&gt;

&lt;h4&gt;
  
  
  Output and Analysis
&lt;/h4&gt;

&lt;p&gt;Running this code produces an output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2023/12/05 12:42:25 value: 1
2023/12/05 12:42:26 waiting...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first log indicates that &lt;code&gt;Value&lt;/code&gt; incremented once. However, the subsequent "waiting..." logs reveal the main goroutine is active but cannot read &lt;code&gt;Value&lt;/code&gt; again due to the deadlock in &lt;code&gt;Execute&lt;/code&gt;. This setup demonstrates a subtle deadlock that does not halt the entire program, exemplifying how deadlocks in multi-threaded applications can be more elusive and challenging to detect.&lt;/p&gt;

&lt;p&gt;This scenario highlights the need for tools like &lt;code&gt;delock&lt;/code&gt;, which can help identify and diagnose deadlocks in more complex, real-world applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Detecting Deadlocks with Delock
&lt;/h3&gt;

&lt;p&gt;In our previous example, the Go runtime couldn’t detect the deadlock because other parts of the program were still running. Now, let's see how &lt;code&gt;delock&lt;/code&gt; changes the game.&lt;/p&gt;

&lt;p&gt;We modify our code to use &lt;code&gt;delock.Mutex&lt;/code&gt; instead of &lt;code&gt;sync.Mutex&lt;/code&gt;. This small change allows &lt;code&gt;delock&lt;/code&gt; to detect and report deadlocks even in complex scenarios where the Go runtime might not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/ietxaniz/delock"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;LockExample&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;    &lt;span class="n"&gt;delock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;LockExample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&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;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;LockExample&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value: %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="n"&gt;LockExample&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="n"&gt;readValueChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;readValueChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;timeoutChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;timeoutChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;

        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;timeoutChan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"waiting..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;readValueChan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value: %d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetValue&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the modified code, the standard locking mechanism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is transformed into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&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 what's happening:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;lockID&lt;/code&gt;: This is a unique identifier for the lock instance within the &lt;code&gt;delock&lt;/code&gt; library. It's used internally to track and manage stack data associated with each lock operation.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;err&lt;/code&gt;: If the &lt;code&gt;Lock()&lt;/code&gt; method takes longer than the defined timeout, it returns an error. This error contains valuable stack trace information indicating where the deadlock might be occurring.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For those concerned about verbosity, using &lt;a href="https://dev.to/ietxaniz/golang-error-handling-introducing-fold-ninja-to-reduce-verbosity-2f0h"&gt;fold-ninja&lt;/a&gt;, a VSCode extension I developed, can streamline the appearance in the editor. The expanded code block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is neatly collapsed to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the code more manageable and less cluttered while maintaining the functionality and robustness provided by &lt;code&gt;delock&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Output and Analysis
&lt;/h4&gt;

&lt;p&gt;When we run this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2023/12/05 12:52:42 value: 1
2023/12/05 12:52:43 waiting...
panic: Deadlock detected
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unlike before, &lt;code&gt;delock&lt;/code&gt; detects the deadlock situation and panics, providing detailed stack trace information. This shows exactly where the deadlock occurs, demonstrating &lt;code&gt;delock&lt;/code&gt;'s ability to uncover hidden issues in multi-threaded applications.&lt;/p&gt;

&lt;p&gt;By using &lt;code&gt;delock&lt;/code&gt;, developers can gain insights into complex deadlock situations, making it a powerful tool for debugging and ensuring smooth concurrency management in Go services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tackling More Complex Deadlock Scenarios
&lt;/h2&gt;

&lt;p&gt;Before we dive into a more intricate deadlock scenario, let's recall the primary function of the &lt;code&gt;delock&lt;/code&gt; tool: &lt;code&gt;delock&lt;/code&gt; is designed to help us identify and understand deadlocks in our Go applications, especially in complex cases where traditional Go runtime detection might fall short. Its ability to provide detailed stack trace information is invaluable in diagnosing and resolving these challenging issues.&lt;/p&gt;

&lt;p&gt;Now, let's explore a scenario involving parent-child relationships within data structures, where deadlocks can be more elusive and difficult to detect.&lt;/p&gt;

&lt;p&gt;Not all deadlock issues are as straightforward as the ones we've explored so far. In real-world applications, especially those involving intricate parent-child relationships between data structures, deadlocks can be more elusive. Let's delve into a more challenging example, where two interconnected data structures, each with its own lock, interact in ways that could potentially lead to deadlock situations.&lt;/p&gt;

&lt;p&gt;In this scenario, we'll examine how parent and child structures, both equipped with mutexes, can create complex locking sequences that might result in deadlocks under certain conditions. This complexity showcases the subtleties of deadlock issues in sophisticated program architectures.&lt;/p&gt;

&lt;p&gt;The following code demonstrates the same scenario using the &lt;code&gt;delock&lt;/code&gt; library. While &lt;code&gt;delock&lt;/code&gt; is instrumental in detecting deadlocks, it's important to note that it's primarily designed for debugging and testing purposes rather than production use. The additional processing &lt;code&gt;delock&lt;/code&gt; performs when acquiring and releasing locks might introduce overhead not suitable for a production environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
    &lt;span class="s"&gt;"time"&lt;/span&gt;

    &lt;span class="s"&gt;"github.com/ietxaniz/delock"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Child&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;     &lt;span class="n"&gt;delock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;
    &lt;span class="n"&gt;value&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt;     &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Parent&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mu&lt;/span&gt;         &lt;span class="n"&gt;delock&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RWMutex&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt;      &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;
    &lt;span class="n"&gt;lastID&lt;/span&gt;     &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;numChanges&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastID&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetChildByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;childID&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&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;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;childID&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;item&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetNumChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&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;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numChanges&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;IncreaseNumChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;numChanges&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RLock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RUnlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IncreaseNumChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;Parent&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Usage: complex &amp;lt;n&amp;gt; &amp;lt;t&amp;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="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Atoi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;2&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&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;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&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="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"child%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sleepMilliseconds&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sleepMilliseconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetChildByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&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;child&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"child%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                    &lt;span class="p"&gt;}&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;i&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="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="n"&gt;lastReadedNumChanges&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;lastReadedNumChanges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetNumChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lastReadedNumChanges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's important to note that while this example runs smoothly under normal, unstressed conditions, it can lead to a deadlock under high-stress scenarios. This behavior can be observed by adjusting the number of runner goroutines (&lt;code&gt;n&lt;/code&gt;) and the sleep duration in milliseconds (&lt;code&gt;t&lt;/code&gt;) in each step. When &lt;code&gt;n&lt;/code&gt; is low and &lt;code&gt;t&lt;/code&gt; is high, the program appears to function correctly. However, increasing &lt;code&gt;n&lt;/code&gt; while decreasing &lt;code&gt;t&lt;/code&gt; creates conditions ripe for a deadlock, demonstrating how system load and operation timing can impact the occurrence of deadlocks in complex systems.&lt;/p&gt;

&lt;p&gt;With the complex example in mind, we'll run the code using various parameters to simulate different stress levels. By altering the number of goroutines (&lt;code&gt;n&lt;/code&gt;) and the sleep duration (&lt;code&gt;t&lt;/code&gt;), we aim to observe the program's behavior under varying conditions. Sometimes, the &lt;code&gt;Value&lt;/code&gt; might increase steadily; other times, it may get stuck, raising suspicions of a deadlock. To confirm these suspicions, we'll switch to using &lt;code&gt;delock&lt;/code&gt;. This will help us determine not only if a deadlock is occurring but also under which specific conditions. Once detected, we'll delve into the code to unravel the reason behind the deadlock, enhancing our understanding of these intricate scenarios.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run ./examples/complex_std/ 50 50
0
105
395
780
780
780
780
780
780

go run ./examples/complex_std/ 50 100
28
28
136
300
496
752
1035
1407
1787
2171
2552
2937
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;50 tasks with 50ms of sleep time seems to have problems while 50 tasks with 100ms of sleep time seems to work properly. So lets execute 50 tasks with 10ms sleep time using delock version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DELOCK_TIMEOUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10000 &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; go run ./examples/complex 50 10
0
...
0
panic: Deadlock detected


&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; READ LOCK &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;
goroutine 52 &lt;span class="o"&gt;[&lt;/span&gt;running]:
github.com/ietxaniz/delock.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;RWMutex&lt;span class="o"&gt;)&lt;/span&gt;.RLock&lt;span class="o"&gt;(&lt;/span&gt;0xc0000b0120&lt;span class="o"&gt;)&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/rwmutex.go:159 +0x65
main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;Parent&lt;span class="o"&gt;)&lt;/span&gt;.GetChildByID&lt;span class="o"&gt;(&lt;/span&gt;0xc0000b0120, 0x3&lt;span class="o"&gt;)&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/examples/complex/main.go:42 +0x38
main.main.func1.1&lt;span class="o"&gt;(&lt;/span&gt;0x0?, 0xa&lt;span class="o"&gt;)&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/examples/complex/main.go:119 +0x55
created by main.main.func1 &lt;span class="k"&gt;in &lt;/span&gt;goroutine 18
        /home/inigo/Documents/Projects/delock/examples/complex/main.go:116 +0x54


&lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; READ LOCK &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;
goroutine 14 &lt;span class="o"&gt;[&lt;/span&gt;running]:
github.com/ietxaniz/delock.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;RWMutex&lt;span class="o"&gt;)&lt;/span&gt;.RLock&lt;span class="o"&gt;(&lt;/span&gt;0xc0000b0120&lt;span class="o"&gt;)&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/rwmutex.go:159 +0x65
main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;Parent&lt;span class="o"&gt;)&lt;/span&gt;.IncreaseNumChanges&lt;span class="o"&gt;(&lt;/span&gt;0xc0000b0120&lt;span class="o"&gt;)&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/examples/complex/main.go:68 +0x2a
main.&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;*&lt;/span&gt;Child&lt;span class="o"&gt;)&lt;/span&gt;.SetValue&lt;span class="o"&gt;(&lt;/span&gt;0xc00007c300, &lt;span class="o"&gt;{&lt;/span&gt;0xc000220020, 0x6&lt;span class="o"&gt;})&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/examples/complex/main.go:95 +0xb1
main.main.func1.1&lt;span class="o"&gt;(&lt;/span&gt;0x0?, 0xa&lt;span class="o"&gt;)&lt;/span&gt;
        /home/inigo/Documents/Projects/delock/examples/complex/main.go:124 +0x15a
created by main.main.func1 &lt;span class="k"&gt;in &lt;/span&gt;goroutine 18
        /home/inigo/Documents/Projects/delock/examples/complex/main.go:116 +0x54

...

&lt;span class="nb"&gt;exit &lt;/span&gt;status 2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"I've omitted several lines from the output because numerous locks were acquired simultaneously in this scenario. However, I retained two critical outputs for analysis. The first one demonstrates typical behavior, but the second raises a red flag, particularly at &lt;strong&gt;examples/complex/main.go:95&lt;/strong&gt;. This line is our key to understanding the deadlock. Let's examine the related code segment, with line numbers for reference:"&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="m"&gt;87&lt;/span&gt;     &lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="m"&gt;88&lt;/span&gt;      &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="m"&gt;89&lt;/span&gt;      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="m"&gt;90&lt;/span&gt;          &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="m"&gt;91&lt;/span&gt;      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="m"&gt;92&lt;/span&gt;      &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="m"&gt;93&lt;/span&gt;
&lt;span class="m"&gt;94&lt;/span&gt;      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
&lt;span class="m"&gt;95&lt;/span&gt;      &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IncreaseNumChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="m"&gt;96&lt;/span&gt;     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Line 95, &lt;code&gt;c.parent.IncreaseNumChanges()&lt;/code&gt; is called while holding a lock. This is a very common mistake. The problem is that &lt;code&gt;IncreaseNumChanges&lt;/code&gt; also acquires a lock. So, if &lt;code&gt;IncreaseNumChanges&lt;/code&gt; is called while holding a lock, it will never be able to acquire the lock and will wait forever. This is a deadlock.&lt;/p&gt;

&lt;p&gt;So, this demonstrates how this tool can effectively help us find deadlocks in our code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution to the Found Deadlock Issue
&lt;/h2&gt;

&lt;p&gt;Upon discovering the deadlock, two potential solutions come to mind. The first is straightforward, while the second aligns more with my preferred approach:&lt;/p&gt;

&lt;h3&gt;
  
  
  Straightforward Solution
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IncreaseNumChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution works by explicitly unlocking before exiting the function. However, it risks future errors if the code is modified and the lock is not properly released in all paths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preferred Solution
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;setValueSafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Parent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mu&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lockID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;SetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setValueSafe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IncreaseNumChanges&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach achieves the same goal but retains the &lt;code&gt;defer&lt;/code&gt; statement for unlocking. This makes the code more robust against future changes and ensures that the lock is always properly released.&lt;/p&gt;

&lt;p&gt;With these corrections applied, the program's output now aligns with our expectations, as evidenced in the terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go run ./examples/complex_solved 100 1
0
404
846
1299
1763
2203
4440
7563
10670
13750
16838
19926
23012
26104
29207
32306
35417
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Repository and Examples
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;delock&lt;/code&gt; library is hosted on GitHub and can be found at &lt;a href="https://github.com/ietxaniz/delock"&gt;https://github.com/ietxaniz/delock&lt;/a&gt;. The repository includes an &lt;code&gt;examples&lt;/code&gt; folder, showcasing various scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;simple&lt;/code&gt; and &lt;code&gt;simple_std&lt;/code&gt;: Demonstrating deadlock detection with &lt;code&gt;delock&lt;/code&gt; and the Go standard library, respectively.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;simple2&lt;/code&gt; and &lt;code&gt;simple2_std&lt;/code&gt;: Highlighting a scenario where Go's standard deadlock detection might fail, but &lt;code&gt;delock&lt;/code&gt; succeeds.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;complex&lt;/code&gt;, &lt;code&gt;complex_std&lt;/code&gt;, and &lt;code&gt;complex_solved&lt;/code&gt;: Exploring more intricate deadlock situations with varying outcomes depending on the detection method used and whether the deadlock issue is resolved.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To run these examples, clone the repository and execute the desired example from the root folder using the command: &lt;code&gt;go run pathToExample&lt;/code&gt;. For instance: &lt;code&gt;go run ./examples/complex&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open Invitation for Collaboration
&lt;/h3&gt;

&lt;p&gt;I welcome any suggestions, feedback, or contributions to the &lt;code&gt;delock&lt;/code&gt; project. Whether it's improving existing features, proposing new ones, or enhancing documentation and examples, your input is valuable. Feel free to raise issues, submit pull requests, or reach out for discussions on potential enhancements.&lt;/p&gt;

</description>
      <category>go</category>
      <category>concurrency</category>
      <category>deadlock</category>
      <category>example</category>
    </item>
    <item>
      <title>Rust Concurrency Explained: Cleaning Code with Traits and Simplifying Services</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Tue, 21 Nov 2023 10:31:17 +0000</pubDate>
      <link>https://dev.to/ietxaniz/rust-concurrency-cleaning-code-with-traits-and-simplifying-services-4lha</link>
      <guid>https://dev.to/ietxaniz/rust-concurrency-cleaning-code-with-traits-and-simplifying-services-4lha</guid>
      <description>&lt;h1&gt;
  
  
  Rust Concurrency: Cleaning Code with Traits and Simplifying Services
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;As I continue my journey with Rust, I've found that revisiting and reviewing my code is not just a best practice but a learning tool in itself. After getting my code to work, I like to take a step back and ponder if there are ways to enhance its readability and efficiency. This reflective practice often leads to significant improvements, making my code cleaner and more understandable.&lt;/p&gt;

&lt;p&gt;Recently, I revisited the initial commit of my project, &lt;code&gt;rust_service_example&lt;/code&gt; (&lt;a href="https://github.com/ietxaniz/rust_service_example/tree/Initial"&gt;link to first commit on GitHub&lt;/a&gt;). While reviewing, I noticed some areas that didn't quite sit right with me. For instance, the process of read-locking and write-locking was taking up more lines than necessary, creating repetitive patterns that I think will cumbersome during code reviews. This realization led me to explore how traits could streamline these aspects, which I'll delve into later in this article.&lt;/p&gt;

&lt;p&gt;Another area I've been questioning is my approach to error handling. Initially, I transitioned from returning a String describing the error to returning &lt;code&gt;Box&amp;lt;dyn Error&amp;gt;&lt;/code&gt;, which seemed like a step in the right direction. However, I'm now experimenting with the &lt;code&gt;anyhow&lt;/code&gt; crate, seeking a more refined method, although I'm still evaluating if it's the best fit.&lt;/p&gt;

&lt;p&gt;Lastly, I made a small change in the main code. By changing the field types in my &lt;code&gt;Service&lt;/code&gt; struct from &lt;code&gt;RwLock&amp;lt;T&amp;gt;&lt;/code&gt; to &lt;code&gt;Arc&amp;lt;RwLock&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;, I was able to implement the &lt;code&gt;Clone&lt;/code&gt; trait. This change has simplified the code in &lt;code&gt;main.rs&lt;/code&gt;, making it more approachable, especially from a beginner's perspective.&lt;/p&gt;

&lt;p&gt;For those interested in seeing the code and its evolution, feel free to explore the repository on &lt;a href="https://github.com/ietxaniz/rust_service_example"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, I'll share these refinements and discuss how they contribute to better, cleaner Rust code. Join me as I navigate through these improvements, and let's learn together how small changes can make a big difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refining Error Handling
&lt;/h2&gt;

&lt;p&gt;In my journey of transitioning from Go to Rust, I've come to realize the nuances in how both languages approach error handling. In my previous articles, I drew parallels between Rust and Go in terms of verbosity and explicitness in managing errors. However, with deeper exploration, I've discovered some key differences and improvements in my Rust coding practice, particularly regarding error handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  Revisiting Rust vs. Go in Error Handling
&lt;/h3&gt;

&lt;p&gt;In Go, the convention of functions returning both a value and an error is a pattern I've always appreciated for its clarity. This approach makes error handling an integral and explicit part of the function's contract. Initially, I viewed Rust's error handling through a similar lens, especially when using &lt;code&gt;match&lt;/code&gt; statements to handle &lt;code&gt;Result&lt;/code&gt; types.&lt;/p&gt;

&lt;p&gt;Rust, however, offers a more streamlined approach with the &lt;code&gt;?&lt;/code&gt; operator. This operator allows for elegant error propagation, reducing the verbosity that comes with manual error checking. Unlike the explicit handling in Go, Rust's &lt;code&gt;?&lt;/code&gt; operator simplifies the code, making it less verbose while still maintaining clarity and predictability.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Shift to &lt;code&gt;anyhow&lt;/code&gt; in Rust Error Handling
&lt;/h3&gt;

&lt;p&gt;My initial foray into Rust error handling involved returning strings as errors. While this method was straightforward, it wasn't in line with Rust's standard practices. I soon learned that a more idiomatic approach in Rust is to return &lt;code&gt;Box&amp;lt;dyn Error&amp;gt;&lt;/code&gt;. This standard has its advantages, primarily its flexibility and compatibility with Rust's error propagation mechanisms.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why &lt;code&gt;Box&amp;lt;dyn Error&amp;gt;&lt;/code&gt;?
&lt;/h4&gt;

&lt;p&gt;In Rust, &lt;code&gt;Box&amp;lt;dyn Error&amp;gt;&lt;/code&gt; is commonly used for error handling, similar to how functions in Go often return an error type. Just like in Go, where a function can return a result and an error, &lt;code&gt;Box&amp;lt;dyn Error&amp;gt;&lt;/code&gt; in Rust provides a dynamic way to handle various error types uniformly. This approach is particularly beneficial in Rust because of the language's &lt;code&gt;?&lt;/code&gt; operator, which enables seamless error propagation.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;Box&amp;lt;dyn Error&amp;gt;&lt;/code&gt; in Rust is akin to Go's error return type in that it allows for a flexible response to different error scenarios. However, Rust's &lt;code&gt;?&lt;/code&gt; operator simplifies error handling further. By adding &lt;code&gt;?&lt;/code&gt; at the end of an operation, Rust can elegantly handle errors without the verbosity typical in Go, where each error requires explicit checking and handling.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Challenge of Mixed Error Types
&lt;/h4&gt;

&lt;p&gt;However, a challenge arises when there's a mix of error types being returned - sometimes a string, other times a boxed error. This inconsistency necessitates additional code for handling and converting errors, leading to a less streamlined and more verbose approach.&lt;/p&gt;

&lt;h4&gt;
  
  
  Embracing &lt;code&gt;anyhow&lt;/code&gt; for Streamlined Error Handling
&lt;/h4&gt;

&lt;p&gt;Recognizing this, I turned to the &lt;code&gt;anyhow&lt;/code&gt; library for a more unified and efficient error handling strategy. &lt;code&gt;anyhow&lt;/code&gt; simplifies the process by allowing the use of a single error type across the codebase. This aligns well with Rust's philosophy of concise and clear error handling while providing the flexibility to handle a wide range of error scenarios.&lt;/p&gt;

&lt;p&gt;Using &lt;code&gt;anyhow&lt;/code&gt;, I can write code that's consistent in its error handling approach, enhancing readability and maintainability. Moreover, &lt;code&gt;anyhow&lt;/code&gt; integrates seamlessly with Rust's &lt;code&gt;?&lt;/code&gt; operator, further reducing verbosity and complexity.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Importance of Consistency and Adaptability
&lt;/h4&gt;

&lt;p&gt;In conclusion, the key takeaway from my experience with error handling is the importance of consistency. Whether it's using &lt;code&gt;Box&amp;lt;dyn Error&amp;gt;&lt;/code&gt;, &lt;code&gt;anyhow&lt;/code&gt;, or another method, sticking to a consistent approach is crucial. It's also essential to remain open to refining your error handling strategy as you gain more insight into Rust's best practices and the tools available. This flexibility allows for continuous improvement in writing more effective and idiomatic Rust code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Benefits of Using &lt;code&gt;anyhow&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Implementing &lt;code&gt;anyhow&lt;/code&gt; in my Rust projects has brought several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Simplified Error Propagation&lt;/strong&gt;: With &lt;code&gt;anyhow&lt;/code&gt;, I can easily return errors from functions without worrying about their specific types. The &lt;code&gt;?&lt;/code&gt; operator works seamlessly with &lt;code&gt;anyhow::Error&lt;/code&gt;, further reducing boilerplate code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Enhanced Readability&lt;/strong&gt;: The use of a single error type declutters the code, making it more readable and maintainable. It's easier to understand and handle errors when they're consistently represented.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Continuous Learning and Refinement
&lt;/h3&gt;

&lt;p&gt;This exploration into Rust's error handling is a testament to the ongoing learning process in programming. What seemed like an established understanding can evolve as you delve deeper into a language's features and best practices. By embracing libraries like &lt;code&gt;anyhow&lt;/code&gt; and utilizing Rust-specific features like the &lt;code&gt;?&lt;/code&gt; operator, I'm refining my approach to writing more idiomatic and efficient Rust code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactoring the &lt;code&gt;Service&lt;/code&gt; Struct for Simplified Usage
&lt;/h2&gt;

&lt;p&gt;In the process of evolving the Rust codebase, a significant refactor was made to the &lt;code&gt;Service&lt;/code&gt; struct. This change not only streamlined the code but also enhanced its readability and maintainability. Let's explore the transformation of the &lt;code&gt;Service&lt;/code&gt; struct and how it positively impacted the usage in &lt;code&gt;main.rs&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Original &lt;code&gt;Service&lt;/code&gt; Struct
&lt;/h3&gt;

&lt;p&gt;Initially, the &lt;code&gt;Service&lt;/code&gt; struct was defined as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;count_thread1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;count_thread2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;write_lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure effectively managed the state using Rust's &lt;code&gt;RwLock&lt;/code&gt; for thread-safe mutable access. However, when it came to sharing &lt;code&gt;Service&lt;/code&gt; instances across threads, the usage in &lt;code&gt;main.rs&lt;/code&gt; required explicit handling of &lt;code&gt;Arc&lt;/code&gt; (Atomic Reference Counting pointers) to manage the shared ownership.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Refactored &lt;code&gt;Service&lt;/code&gt; Struct
&lt;/h2&gt;

&lt;p&gt;To simplify this pattern, the &lt;code&gt;Service&lt;/code&gt; struct was refactored as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(Clone)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;count_thread1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;count_thread2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;write_lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By incorporating &lt;code&gt;Arc&amp;lt;RwLock&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt; directly into the struct and deriving the &lt;code&gt;Clone&lt;/code&gt; trait, the &lt;code&gt;Service&lt;/code&gt; struct became more ergonomic to use. This change abstracts away the explicit handling of &lt;code&gt;Arc&lt;/code&gt;, making the struct more straightforward to clone and share across threads.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplified Usage in &lt;code&gt;main.rs&lt;/code&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Before the Refactor
&lt;/h4&gt;

&lt;p&gt;Originally, sharing an instance of &lt;code&gt;Service&lt;/code&gt; across threads required explicitly creating an &lt;code&gt;Arc&lt;/code&gt; and then cloning it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  After the Refactor
&lt;/h4&gt;

&lt;p&gt;With the refactored &lt;code&gt;Service&lt;/code&gt; struct, the code in &lt;code&gt;main.rs&lt;/code&gt; becomes cleaner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This refactoring makes the code more intuitive and straightforward. The cloning of the service instance is now a simple method call, enhancing the overall readability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Traits for Code Simplification and Cleaning
&lt;/h2&gt;

&lt;p&gt;One of the most powerful features of Rust is its trait system, which allows for code abstraction and reuse in a way that's both efficient and elegant. In this part of the article, I'll demonstrate how we can leverage traits to simplify and clean up our code. Our goal is to transform a common pattern in our codebase into a more concise and readable form, without altering the application's functionality.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Objective: Streamlining Lock Operations
&lt;/h3&gt;

&lt;p&gt;Consider this snippet from our current codebase:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.count&lt;/span&gt;
            &lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to read-lock count: {}"&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we're acquiring a read lock on a resource and handling potential errors. While this code is functional, it's also somewhat verbose and repetitive, especially if similar patterns are used throughout the application.&lt;/p&gt;

&lt;p&gt;Now, let's look at how we can streamline this with the help of a custom trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.count&lt;/span&gt;&lt;span class="nf"&gt;.lock_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"count"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this new approach, the code becomes much more succinct and clear. The error handling is still there, but it's abstracted away by our trait, making the main logic easier to read and maintain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplifying Lock Operations with the &lt;code&gt;LockExt&lt;/code&gt; Trait in Rust
&lt;/h3&gt;

&lt;p&gt;In Rust, managing locks, especially with &lt;code&gt;RwLock&lt;/code&gt;, can often involve verbose and repetitive error handling. To address this, let's explore the &lt;code&gt;LockExt&lt;/code&gt; trait, a solution that streamlines these operations. This trait is a great example of how Rust's powerful trait system can be used to enhance code readability and efficiency.&lt;/p&gt;

&lt;p&gt;Here's the code for the &lt;code&gt;LockExt&lt;/code&gt; trait:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;RwLockReadGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RwLockWriteGuard&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;trait&lt;/span&gt; &lt;span class="n"&gt;LockExt&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lock_write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLockWriteGuard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lock_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLockReadGuard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;LockExt&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lock_write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLockWriteGuard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;anyhow!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock {}: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;lock_read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLockReadGuard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;anyhow!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to read-lock {}: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This trait abstracts the process of acquiring read and write locks, simplifying error handling. Instead of writing lengthy error handling every time a lock is acquired, the &lt;code&gt;LockExt&lt;/code&gt; trait encapsulates this in two concise methods: &lt;code&gt;lock_write&lt;/code&gt; and &lt;code&gt;lock_read&lt;/code&gt;. And allows the simplification we where looking for at the beginning of this section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Emphasizing the Choice of &lt;code&gt;anyhow&lt;/code&gt; in the &lt;code&gt;LockExt&lt;/code&gt; Trait
&lt;/h3&gt;

&lt;p&gt;Having previously discussed the nuances of error handling in Rust and the advantages of utilizing libraries like &lt;code&gt;anyhow&lt;/code&gt;, the implementation of the &lt;code&gt;LockExt&lt;/code&gt; trait further exemplifies why &lt;code&gt;anyhow&lt;/code&gt; was the preferred choice. This trait demonstrates the practical application of &lt;code&gt;anyhow&lt;/code&gt; in a real-world scenario, highlighting its benefits in streamlining error handling.&lt;/p&gt;

&lt;h4&gt;
  
  
  Simplified Error Handling with &lt;code&gt;anyhow&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Consider the &lt;code&gt;lock_write&lt;/code&gt; function using &lt;code&gt;anyhow&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;RwLockWriteGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;lock_write&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLockWriteGuard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&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="nd"&gt;anyhow!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock {}: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implementation leverages &lt;code&gt;anyhow&lt;/code&gt; for its concise and expressive error reporting. The &lt;code&gt;anyhow!&lt;/code&gt; macro enables quick conversion of errors into an &lt;code&gt;anyhow::Error&lt;/code&gt;, complete with a descriptive message. This approach significantly reduces boilerplate and enhances readability.&lt;/p&gt;

&lt;p&gt;Contrast this with the more traditional approach without &lt;code&gt;anyhow&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;RwLockWriteGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;MyError&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Implementations for MyError...&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;lock_write&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RwLockWriteGuard&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;lock&lt;/span&gt;&lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.map_err&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="nn"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;MyError&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock {}: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&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;as&lt;/span&gt; &lt;span class="nb"&gt;Box&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;dyn&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the necessity of a custom error type (&lt;code&gt;MyError&lt;/code&gt;) and the additional code for error management increases the complexity, making the function more verbose.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Consistent Error Handling with &lt;code&gt;anyhow&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The transition to using &lt;code&gt;anyhow&lt;/code&gt; for error handling in Rust represents more than just a technical refinement; it signifies an embrace of idiomatic Rust practices that prioritize clarity, brevity, and robustness. This shift not only made the error handling in my codebase more consistent but also underscored the importance of adaptability and continuous learning in software development. As Rust continues to evolve, so too should our approaches to coding within its ecosystem. The adoption of &lt;code&gt;anyhow&lt;/code&gt; is a testament to this philosophy, showcasing a commitment to write code that is not only functional but also clean and maintainable.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Impact of Refactoring &lt;code&gt;Service&lt;/code&gt; Struct
&lt;/h3&gt;

&lt;p&gt;Embedding &lt;code&gt;Arc&lt;/code&gt; directly into the &lt;code&gt;Service&lt;/code&gt; struct and leveraging the &lt;code&gt;Clone&lt;/code&gt; trait proved to be a subtle yet impactful change. This refactoring underscores the philosophy of smart struct design in Rust—where the focus is not just on the functionality but also on how the structure of the code can lead to more intuitive and elegant usage patterns. By making these adjustments, the &lt;code&gt;Service&lt;/code&gt; struct became more aligned with Rust's design principles, offering a more streamlined and idiomatic way of handling shared state in concurrent environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Leveraging Traits for Code Simplification
&lt;/h3&gt;

&lt;p&gt;The implementation of the &lt;code&gt;LockExt&lt;/code&gt; trait is a prime example of Rust's powerful trait system at work. It highlights how traits can be used not just for defining shared behavior, but also for simplifying and cleaning up code. This approach is particularly useful in Rust, where managing complexity is key to writing effective programs. By abstracting repetitive patterns into a trait, the codebase becomes more organized, allowing for easier maintenance and future enhancements. The &lt;code&gt;LockExt&lt;/code&gt; trait, therefore, is not just a utility but a representation of the Rust philosophy of making code more modular and expressive.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>concurrency</category>
      <category>cleancode</category>
    </item>
    <item>
      <title>Rust Concurrency Explained: A Beginner's Guide to Arc and Mutex</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Fri, 17 Nov 2023 19:47:32 +0000</pubDate>
      <link>https://dev.to/ietxaniz/rust-concurrency-explained-a-beginners-guide-to-arc-and-mutex-13ca</link>
      <guid>https://dev.to/ietxaniz/rust-concurrency-explained-a-beginners-guide-to-arc-and-mutex-13ca</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Jumping into Rust programming has been quite a ride. At first, it felt a bit like trying to solve a puzzle, especially when it came to understanding how Rust handles data. The borrowing concept? Got it, no big deal. But things got trickier when I started wondering how you could let two parts of your program share and change the same data without stepping on each other's toes. That's where &lt;code&gt;Arc&lt;/code&gt; and &lt;code&gt;Mutex&lt;/code&gt; come into play.&lt;/p&gt;

&lt;p&gt;So, I thought, why not make an example to figure this out? The idea was to set up two threads in a Rust program, with both threads messing around with the same bunch of data. They would each bump up a couple of counters - one that they both share and another that's just for themselves. Then, right after each bump, we'd take a look at where the counters stand.&lt;/p&gt;

&lt;p&gt;This wasn't just about writing some code; it was more about getting my head around Rust's way of handling data when multiple things are happening at once. Here's the story of what I did, what I learned, and how it all works.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Application Idea: Playing with Counters
&lt;/h2&gt;

&lt;p&gt;So, what's this example all about? Well, it's pretty straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two Threads, Two Tasks&lt;/strong&gt;: Imagine two little workers (threads) in our program. They're both doing a similar job but in their own way. One is labeled &lt;code&gt;thread1&lt;/code&gt; and the other &lt;code&gt;thread2&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What They Do&lt;/strong&gt;: Each time they get to work (&lt;code&gt;thread1&lt;/code&gt; and &lt;code&gt;thread2&lt;/code&gt; doing their thing), they do a couple of things:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;thread1&lt;/code&gt; ups the numbers on two counters: a shared one (&lt;code&gt;count&lt;/code&gt;) and its own (&lt;code&gt;count_thread1&lt;/code&gt;). Then it shouts out (prints) the current score.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;thread2&lt;/code&gt; does pretty much the same, but with &lt;code&gt;count&lt;/code&gt; (the shared one) and &lt;code&gt;count_thread2&lt;/code&gt; (its own personal counter).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep It DRY (Don't Repeat Yourself)&lt;/strong&gt;: I wanted to be smart about this and not write the same piece of code twice for showing the score. So, both threads use the same function to print the status. It's like they're using the same megaphone to announce their results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Playing Nice with Sharing&lt;/strong&gt;: Here's the catch, though. When one thread is updating the counters and about to announce the score, we don't want the other one to barge in and mess things up. It's like saying, "Hold on, let me finish talking before you jump in." This means we need to be a bit clever about locking things up.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the gist of our little Rust adventure. Two threads, a few counters, and making sure they don't trip over each other while they're at it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explaining the Service Code: Mutex Magic in Rust
&lt;/h2&gt;

&lt;p&gt;Alright, let's dive into the heart of our Rust code - the &lt;code&gt;Service&lt;/code&gt; struct. This is where the magic happens, and by magic, I mean carefully managing access to shared data with mutexes. Here's the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;count_thread1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;count_thread2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;write_lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;RwLock&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;u8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Service&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;RwLock&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;count_thread1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;RwLock&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;count_thread2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;RwLock&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;write_lock&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;RwLock&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;get_counts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.count&lt;/span&gt;
            &lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to read-lock count: {}"&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;count_thread1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.count_thread1&lt;/span&gt;
            &lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to read-lock count_thread1: {}"&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;count_thread2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.count_thread2&lt;/span&gt;
            &lt;span class="nf"&gt;.read&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to read-lock write_lock: {}"&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count_thread1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count_thread2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;increment_counts_thread1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.count&lt;/span&gt;
            &lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock count: {}"&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;count_thread1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.count_thread1&lt;/span&gt;
            &lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock count_thread1: {}"&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;write_lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.write_lock&lt;/span&gt;
            &lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock write_lock: {}"&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="o"&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;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;count_thread1&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;write_lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count_thread1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.get_counts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;increment_counts_thread2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.count&lt;/span&gt;
            &lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock count: {}"&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;count_thread2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.count_thread2&lt;/span&gt;
            &lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock count_thread2: {}"&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="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;write_lock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;
            &lt;span class="py"&gt;.write_lock&lt;/span&gt;
            &lt;span class="nf"&gt;.write&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.map_err&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="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to write-lock write_lock: {}"&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="o"&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;count&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;count_thread2&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count_thread2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;write_lock&lt;/span&gt; &lt;span class="o"&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;self&lt;/span&gt;&lt;span class="nf"&gt;.get_counts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Breaking Down the Code
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Counters for Each Thread&lt;/strong&gt;: We've got three counters here - &lt;code&gt;count&lt;/code&gt;, &lt;code&gt;count_thread1&lt;/code&gt;, and &lt;code&gt;count_thread2&lt;/code&gt;. The first one is shared between both threads, while the other two are individual to each thread. Each counter is wrapped in a &lt;code&gt;Mutex&lt;/code&gt;. Why? Because &lt;code&gt;Mutex&lt;/code&gt; ensures that only one thread can mess with the data at a time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The &lt;code&gt;write_lock&lt;/code&gt; Mutex&lt;/strong&gt;: This little guy is the key to making sure our print status function doesn't get interrupted by the other thread. We're using it to lock down the entire increment operation, from start to finish, including the print part. And to keep the compiler happy (and avoid warnings about unused variables), we're assigning a value (&lt;code&gt;1&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt;) to &lt;code&gt;write_lock&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lock Order Consistency&lt;/strong&gt;: Notice something about how we lock our counters? We always lock &lt;code&gt;count&lt;/code&gt; first, then &lt;code&gt;count_thread1&lt;/code&gt; or &lt;code&gt;count_thread2&lt;/code&gt;. This is crucial. Locking in the same order every time is a simple yet effective way to dodge deadlocks. If you start locking in different orders in different parts of your code, you're setting up a classic deadlock scenario.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Choosing RwLock Over Mutex: A Consideration of Context
&lt;/h3&gt;

&lt;p&gt;In the Rust ecosystem, we often use &lt;code&gt;Mutex&lt;/code&gt; for safe, exclusive access to data across multiple threads. Think of &lt;code&gt;Mutex&lt;/code&gt; as a way to say, "One at a time, please," ensuring that only one thread can access the data at any given moment. It's a straightforward, foolproof approach to concurrency.&lt;/p&gt;

&lt;p&gt;But then there's &lt;code&gt;RwLock&lt;/code&gt;, a slightly more complex cousin of &lt;code&gt;Mutex&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  The Subtlety of RwLock
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reading and Writing&lt;/strong&gt;: &lt;code&gt;RwLock&lt;/code&gt; allows multiple threads to read data at the same time, which can be a big win for performance if you have a lot of read operations. However, it still ensures that write operations get exclusive access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;In Our Case&lt;/strong&gt;: While our current example might not have simultaneous reads, we chose &lt;code&gt;RwLock&lt;/code&gt; to illustrate how it could be beneficial in a broader application context. It's about understanding the tools at your disposal and choosing the right one for the right job.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The Practical Angle
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Why Not Just Stick with Mutex?&lt;/strong&gt;: You might wonder why we didn't just use &lt;code&gt;Mutex&lt;/code&gt; since our example doesn’t explicitly require the concurrent read capabilities of &lt;code&gt;RwLock&lt;/code&gt;. The reason is twofold: firstly, to demonstrate the capabilities of &lt;code&gt;RwLock&lt;/code&gt; for educational purposes, and secondly, to prepare the code for potential scalability where concurrent reads might become more relevant.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Big Picture&lt;/strong&gt;: In a larger application, where you might have numerous threads frequently reading data, the benefits of &lt;code&gt;RwLock&lt;/code&gt; become more pronounced. By allowing concurrent reads, &lt;code&gt;RwLock&lt;/code&gt; can significantly enhance performance, reducing the waiting time for threads that just want to read data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choosing &lt;code&gt;RwLock&lt;/code&gt; in our example is a nod to these broader considerations. It’s about anticipating future needs and understanding how different concurrency tools can be leveraged in various scenarios. This is a key part of thinking like a Rustacean — not just solving the problem at hand but doing so in a way that's efficient, scalable, and idiomatic to Rust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explaining the &lt;code&gt;main&lt;/code&gt; Function and the Role of &lt;code&gt;Arc&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;In our Rust application, the &lt;code&gt;main&lt;/code&gt; function is where we see the concurrency in action. Let's dissect how it uses &lt;code&gt;Arc&lt;/code&gt; to enable multiple threads to interact with the same instance of our &lt;code&gt;Service&lt;/code&gt; struct.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;main&lt;/code&gt; Function Code
&lt;/h3&gt;

&lt;p&gt;Here's what our &lt;code&gt;main&lt;/code&gt; function looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;service2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Arc&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;thread1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&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;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;service1&lt;/span&gt;&lt;span class="nf"&gt;.increment_counts_thread1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread 1: Iteration {}: Counts = {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nf"&gt;Err&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread 1: Iteration {}: Error = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&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="c1"&gt;// Handle error, e.g., retry, log, or break&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_millis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;thread2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;||&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;i&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;service2&lt;/span&gt;&lt;span class="nf"&gt;.increment_counts_thread2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread 2: Iteration {}: Counts = {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="nf"&gt;Err&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread 2: Iteration {}: Error = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&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="c1"&gt;// Handle error, e.g., retry, log, or break&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="nn"&gt;thread&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_millis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Err&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thread1&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread 1 panicked: {:?}"&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="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nf"&gt;Err&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;thread2&lt;/span&gt;&lt;span class="nf"&gt;.join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread 2 panicked: {:?}"&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Understanding &lt;code&gt;Arc&lt;/code&gt; in Rust
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Arc: A Smart Pointer for Concurrency&lt;/strong&gt;: &lt;code&gt;Arc&lt;/code&gt; stands for Atomic Reference Counting. It's a type of smart pointer in Rust, which means it keeps track of how many references exist to a certain piece of data. Once all references are gone, the data is automatically cleaned up. This is super handy in avoiding memory leaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why Use &lt;code&gt;Arc&lt;/code&gt;?&lt;/strong&gt;: In a multi-threaded context, we need a way to safely share data between threads. &lt;code&gt;Arc&lt;/code&gt; allows multiple threads to own a reference to the same data, ensuring that the data stays alive as long as at least one thread is using it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thread-Safety&lt;/strong&gt;: &lt;code&gt;Arc&lt;/code&gt; is thread-safe, meaning it can be used across multiple threads without the risk of causing data races. This is crucial in our example where multiple threads are accessing and modifying the shared &lt;code&gt;Service&lt;/code&gt; instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Threads in Action
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Creating Threads&lt;/strong&gt;: We spawn two threads, &lt;code&gt;thread1&lt;/code&gt; and &lt;code&gt;thread2&lt;/code&gt;. Each thread is given a cloned reference to our &lt;code&gt;Service&lt;/code&gt; instance (&lt;code&gt;service1&lt;/code&gt; and &lt;code&gt;service2&lt;/code&gt;). This cloning is done using &lt;code&gt;Arc::clone&lt;/code&gt;, which increments the reference count rather than copying the actual data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interacting with Shared Data&lt;/strong&gt;: Inside each thread, we call either &lt;code&gt;increment_counts_thread1&lt;/code&gt; or &lt;code&gt;increment_counts_thread2&lt;/code&gt;. These methods modify the shared data in a controlled manner, thanks to our &lt;code&gt;RwLock&lt;/code&gt; implementation in the &lt;code&gt;Service&lt;/code&gt; struct.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expected Outcomes&lt;/strong&gt;: As each thread performs its operations, we expect the shared counter (&lt;code&gt;count&lt;/code&gt;) to be incremented by both threads, whereas &lt;code&gt;count_thread1&lt;/code&gt; and &lt;code&gt;count_thread2&lt;/code&gt; are exclusive to their respective threads. The threads also print out the current state of these counters after each increment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, &lt;code&gt;Arc&lt;/code&gt; in our &lt;code&gt;main&lt;/code&gt; function demonstrates Rust's powerful and safe approach to concurrency. By allowing multiple threads to share ownership of data, &lt;code&gt;Arc&lt;/code&gt; enables concurrent access while ensuring that the data lives as long as it's needed and no longer. This, combined with the thread-safe operations on our &lt;code&gt;Service&lt;/code&gt; struct, showcases a typical pattern for managing shared state in multi-threaded Rust applications.&lt;/p&gt;

&lt;h4&gt;
  
  
  Seeing It in Action: Output of the Program
&lt;/h4&gt;

&lt;p&gt;After understanding the roles of &lt;code&gt;Arc&lt;/code&gt;, &lt;code&gt;RwLock&lt;/code&gt;, and our thread setup, let's see what happens when we actually run the program. Here's the output you can expect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;cargo run &lt;span class="nb"&gt;.&lt;/span&gt;
   Compiling service_example v0.1.0 &lt;span class="o"&gt;(&lt;/span&gt;/home/inigo/Documents/Tutorials/RUST/service_example&lt;span class="o"&gt;)&lt;/span&gt;
    Finished dev &lt;span class="o"&gt;[&lt;/span&gt;unoptimized + debuginfo] target&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in &lt;/span&gt;0.37s
     Running &lt;span class="sb"&gt;`&lt;/span&gt;target/debug/service_example .&lt;span class="sb"&gt;`&lt;/span&gt;
Thread 1: Iteration 0: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;1, 1, 0&lt;span class="o"&gt;)&lt;/span&gt;
Thread 2: Iteration 0: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;2, 1, 1&lt;span class="o"&gt;)&lt;/span&gt;
Thread 1: Iteration 1: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;3, 2, 1&lt;span class="o"&gt;)&lt;/span&gt;
Thread 2: Iteration 1: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;4, 2, 2&lt;span class="o"&gt;)&lt;/span&gt;
Thread 1: Iteration 2: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;5, 3, 2&lt;span class="o"&gt;)&lt;/span&gt;
Thread 2: Iteration 2: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;6, 3, 3&lt;span class="o"&gt;)&lt;/span&gt;
Thread 1: Iteration 3: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;7, 4, 3&lt;span class="o"&gt;)&lt;/span&gt;
Thread 2: Iteration 3: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;8, 4, 4&lt;span class="o"&gt;)&lt;/span&gt;
Thread 1: Iteration 4: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;9, 5, 4&lt;span class="o"&gt;)&lt;/span&gt;
Thread 2: Iteration 4: Counts &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;10, 5, 5&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This output clearly shows how the counters are incremented by each thread. Notice how the shared counter (&lt;code&gt;count&lt;/code&gt;) increases with each operation, regardless of which thread is executing, while the individual counters (&lt;code&gt;count_thread1&lt;/code&gt; and &lt;code&gt;count_thread2&lt;/code&gt;) are incremented only by their respective threads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Management in Rust: Embracing Verbosity for Clarity
&lt;/h2&gt;

&lt;p&gt;When transitioning to Rust from a language like Go, one thing you might find familiar is the verbosity in error handling. Rust, much like Go, emphasizes explicit and clear error management, though the styles differ slightly. Let's delve into how this plays out in Rust using our example, and why embracing this verbosity can be beneficial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rust's Explicit Error Handling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Explicit is Better than Implicit&lt;/strong&gt;: Rust enforces an explicit approach to error handling. Unlike languages that use exceptions, Rust requires you to acknowledge and handle potential errors at every step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Avoiding &lt;code&gt;.unwrap()&lt;/code&gt; in Production&lt;/strong&gt;: While &lt;code&gt;.unwrap()&lt;/code&gt; is convenient for quick tests or examples, it's risky in production code because it causes the program to panic in case of an error. Rust encourages handling errors gracefully to avoid unexpected crashes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Verbosity in Rust vs. Go
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clear and Predictable Code&lt;/strong&gt;: Rust’s verbose error handling, akin to Go's, ensures that your code is clear about how it deals with various failure scenarios. This explicitness leads to more predictable and maintainable code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Our Code's Error Handling Approach&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;service1&lt;/span&gt;&lt;span class="nf"&gt;.increment_counts_thread1&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread 1: Iteration {}: Counts = {:?}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;Err&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;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;eprintln!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Thread 1: Iteration {}: Error = {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;i&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;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&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;
&lt;strong&gt;The Use of &lt;code&gt;match&lt;/code&gt;&lt;/strong&gt;: We use &lt;code&gt;match&lt;/code&gt; to handle the &lt;code&gt;Result&lt;/code&gt; type returned by our functions. This way, we explicitly define the flow for both successful and error outcomes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Balancing Verbosity and Practicality
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context Matters&lt;/strong&gt;: There are times when using &lt;code&gt;.unwrap()&lt;/code&gt; might be okay, such as in prototype code or when an error is impossible by logic. However, as a general rule, explicit error handling is preferred.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Familiarity Over Time&lt;/strong&gt;: If you're used to Go's error handling, Rust's approach will feel familiar, though it may take some time to adapt to the nuances. Eventually, you'll likely appreciate the robustness it brings to your programs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In summary, Rust's approach to error handling, while verbose, shares similarities with Go's explicit style. This verbosity is a small price to pay for the clarity and safety it brings to your code. As you grow more accustomed to Rust's patterns, you'll find that this explicitness becomes an invaluable tool in writing reliable, bug-resistant applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions: Navigating the Learning Path in Rust
&lt;/h2&gt;

&lt;p&gt;As we come to the end of this post, it's clear that diving into Rust's world, especially its approach to concurrency, is both challenging and rewarding. I'm by no means an expert in Rust — just someone who's starting small and grappling with concepts that initially seemed daunting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Embracing Rust's Concurrency Model
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Starting Small&lt;/strong&gt;: My journey in Rust began with tackling small, challenging concepts. This exploration into &lt;code&gt;Arc&lt;/code&gt;, &lt;code&gt;RwLock&lt;/code&gt;, and threading is a part of that journey, an attempt to understand the depths of Rust's concurrency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Safety First&lt;/strong&gt;: One of the most significant learnings from this exercise is the importance Rust places on safety, particularly in concurrent environments. The language's design nudges you towards patterns that prevent common errors like data races.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Beginner's Experience
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;From Confusion to Clarity&lt;/strong&gt;: As a beginner, the complexity of ownership, borrowing, and concurrency in Rust can be quite overwhelming. But, as with any new skill, the confusion gradually gives way to clarity with practice and patience.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Community Support&lt;/strong&gt;: One thing that stands out in my learning process is the Rust community's support. Whether it's through forums, documentation, or open-source contributions, there's always help available.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  A Small Step in a Larger Journey
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Continual Learning&lt;/strong&gt;: This example, which I found challenging initially, represents just a small step in the broader journey of mastering Rust. It’s a testament to starting with what seems tough and breaking it down into manageable pieces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encouragement for Fellow Learners&lt;/strong&gt;: To those who are also on their beginning stages with Rust, keep at it. The initial hurdles are part of the process, and every challenge overcome is a stride towards becoming a proficient Rustacean.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Explore the Code
&lt;/h3&gt;

&lt;p&gt;If you're curious to see how the theory translates into code, or if you want to try your hand at modifying and playing with it, check out the repository on GitHub. It's a space for learning, experimenting, and sharing insights.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ietxaniz/rust_service_example"&gt;GitHub Repository Link&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;In summary, my journey with Rust is still in its early stages, filled with learning and discovery. This example is a reflection of that — a small piece of a much larger puzzle. As I continue to learn, I look forward to uncovering more such pieces, understanding them, and fitting them together in the beautiful tapestry that is Rust programming.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>concurrency</category>
    </item>
    <item>
      <title>Golang Error Handling: Introducing Fold Ninja to Reduce Verbosity</title>
      <dc:creator>Iñigo Etxaniz</dc:creator>
      <pubDate>Tue, 14 Nov 2023 09:03:55 +0000</pubDate>
      <link>https://dev.to/ietxaniz/golang-error-handling-introducing-fold-ninja-to-reduce-verbosity-2f0h</link>
      <guid>https://dev.to/ietxaniz/golang-error-handling-introducing-fold-ninja-to-reduce-verbosity-2f0h</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to Go Error Handling
&lt;/h2&gt;

&lt;p&gt;As a Go developer, one aspect of the language that I deeply appreciate is its approach to error handling. It's designed to be reliable, thorough, and encourages good programming practices. Here are some key points I particularly like about Go's error handling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Immediate Error Handling&lt;/strong&gt;: In Go, errors are handled as soon as they occur. This immediacy ensures that issues are addressed promptly, enhancing the stability and reliability of applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Comprehensive Error Consideration&lt;/strong&gt;: When coding in Go, all potential errors are taken into account. This thoroughness ensures that we're always aware and prepared for possible failure points in our code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduced Unexpected Errors&lt;/strong&gt;: With the correct programming approach, unexpected errors (or panics) are almost a rarity in Go. This is a testament to the language's robustness and our ability to control error flows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ease in Tracing Errors&lt;/strong&gt;: Finding the source of a problem in Go is generally straightforward, especially if error descriptions are clear and informative. Often, a simple search in VSCode with the text of the error leads you right to the issue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Tools for Error Analysis&lt;/strong&gt;: Go also provides powerful tools to understand the sequence of events leading to an error. For instance, here's a snippet showing how you can use Go's runtime package to capture a stack trace just after an error occurs:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;96000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;stackItems&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;stackData&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c"&gt;// Further processing of stackData...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet captures the current goroutine's stack trace and splits it into readable segments, allowing for a detailed analysis of the error's context.&lt;/p&gt;

&lt;p&gt;In summary, Go's error handling is not just a feature; it's a cornerstone of the language's design philosophy, promoting robust and reliable code. However, despite these advantages, there's one aspect that can be challenging: verbosity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Challenge of Verbosity in Go Error Handling
&lt;/h2&gt;

&lt;p&gt;While Go's error handling is effective, it introduces a challenge that I've personally grappled with: verbosity. This becomes particularly evident during the code review process. In my programming practice, I adhere to a principle where the code should largely explain itself. This is achieved through well-thought-out function and variable names, along with breaking down logic into smaller, descriptively named functions. The aim is always to reduce reliance on comments and make the code as self-explanatory as possible.&lt;/p&gt;

&lt;p&gt;However, the verbosity inherent in Go's error handling often poses a hurdle to this approach. Let's consider a common scenario: you're reviewing code and trying to grasp the core algorithm. Each function call accompanied by error handling adds layers of additional lines. These lines, while crucial for robustness, can distract from the main logic flow. The result? It becomes more challenging to quickly understand the essence of what the code is doing.&lt;/p&gt;

&lt;p&gt;Here's a typical example illustrating this point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;
    &lt;span class="s"&gt;"compress/gzip"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/base64"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// gunzipB64ToString takes a base64 encoded string that represents gzip-compressed data,&lt;/span&gt;
&lt;span class="c"&gt;// decodes it, unzips it, and returns the resulting string.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;gunzipB64ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b64Data&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;decodedBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StdEncoding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecodeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b64Data&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error decoding base64 data: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decodedBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;gzipReader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error creating new gzip reader: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;gzipReader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;unzippedBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gzipReader&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error reading unzipped data: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unzippedBytes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;encodedString&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"H4sIAAAAAAAA/8tIzcnJBwCGphA2BQAAAA=="&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gunzipB64ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encodedString&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Decompressed and decoded string:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this snippet, the core operations – decoding a base64 string and unzipping it – are fairly straightforward. Yet, the error handling associated with each step nearly doubles the number of lines in the function. This added verbosity, while crucial for ensuring the robustness and reliability of the operation, can overshadow the main functionality, especially when viewed within the broader context of a larger application.&lt;/p&gt;

&lt;p&gt;This isn't just a matter of aesthetics; it has practical implications for code readability and maintenance. When reviewing code, the clarity of the core logic can be clouded by the repetitive nature of error checks. This can make the review process more time-consuming and cumbersome, and sometimes, important aspects of the logic might be overlooked due to the clutter.&lt;/p&gt;

&lt;p&gt;As a developer who values clean, self-explanatory code, I found this aspect of Go programming particularly challenging. It was important to me to find a solution that would align with my coding philosophy of minimalistic, clear code, while still respecting Go's rigorous approach to error handling.&lt;/p&gt;

&lt;p&gt;Now, let's see how the same function looks when folded using "Fold Ninja":&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"bytes"&lt;/span&gt;
    &lt;span class="s"&gt;"compress/gzip"&lt;/span&gt;
    &lt;span class="s"&gt;"encoding/base64"&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"io"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// gunzipB64ToString takes a base64 encoded string that represents gzip-compressed data,&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;gunzipB64ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b64Data&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;decodedBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StdEncoding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DecodeString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b64Data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewBuffer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decodedBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;gzipReader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gzip&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;gzipReader&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;unzippedBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gzipReader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unzippedBytes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;encodedString&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"H4sIAAAAAAAA/8tIzcnJBwCGphA2BQAAAA=="&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gunzipB64ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encodedString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Decompressed and decoded string:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With "Fold Ninja," the error handling blocks are neatly folded away. This leaves us with a view that emphasizes the core logic of the function. The error handling is still there, just one click away if we need to inspect it, but it no longer dominates the visual landscape of the code. This folding makes it much easier to focus on and understand the primary operations of the function, especially during code reviews or when navigating through a large codebase.&lt;/p&gt;

&lt;p&gt;The difference is clear – what was once a multi-line, error-handling-heavy function is now a concise, easily digestible piece of code. This not only enhances the readability but also aligns with the philosophy of writing self-explanatory code that focuses on the core logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Development of Fold-Ninja
&lt;/h2&gt;

&lt;p&gt;After recognizing the challenges posed by verbosity in Go error handling, I developed "Fold Ninja," a Visual Studio Code extension tailored to enhance code readability and streamline the review process. The primary goal of Fold Ninja is to reduce the visual noise created by excessive information, particularly verbose error management sections in Go files.&lt;/p&gt;

&lt;p&gt;Fold Ninja operates in three modes, each designed to cater to different needs during code analysis and review:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Inactive&lt;/strong&gt;: In this mode, Fold Ninja is dormant, showing the code in its original, unaltered form.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compact&lt;/strong&gt;: This is where the extension truly shines. Compact mode automatically folds away verbose parts of the code, including comments and error management blocks. This mode significantly declutters the code, presenting a focused view that highlights the main logic.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Expanded&lt;/strong&gt;: In this mode, all previously compacted sections are unfolded, making every part of the code, including comments and error handling routines, visible again.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Switching between these modes is a simple click on the status bar item, making it user-friendly. This flexibility allows developers to quickly shift views based on their current task – whether they're deep diving into a detailed analysis or doing a high-level code review.&lt;/p&gt;

&lt;p&gt;When working in compact mode, extension is only activated when user activates a file. So, when coding the extension will not update the view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try Fold-Ninja and Contribute
&lt;/h2&gt;

&lt;p&gt;I invite you to try &lt;a href="https://marketplace.visualstudio.com/items?itemName=ietxaniz.fold-ninja"&gt;Fold Ninja&lt;/a&gt; and experience firsthand how it can enhance your Go coding and review process. You can find the extension on the Visual Studio Marketplace and explore its source code on &lt;a href="https://github.com/ietxaniz/vscode-fold-ninja"&gt;GitHub&lt;/a&gt;. Your feedback and contributions are highly valued. If you have suggestions or encounter any issues, please feel free to open an issue on the GitHub repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;In summary, Fold Ninja embodies my philosophy of clean, self-explanatory code. It offers a practical solution to the verbosity challenge in Go, allowing developers to focus on what truly matters in their code. As we continue to evolve and improve our tools, I believe that we can make Go development an even more enjoyable and efficient experience. Thank you for reading, and I look forward to your thoughts and contributions to Fold Ninja.&lt;/p&gt;

</description>
      <category>go</category>
      <category>errors</category>
      <category>vscode</category>
      <category>verbosity</category>
    </item>
  </channel>
</rss>
