<?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: Aniello Musella</title>
    <description>The latest articles on DEV Community by Aniello Musella (@animusna).</description>
    <link>https://dev.to/animusna</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%2F447424%2F4d6f4d29-7a0a-438c-bbe2-99ac1bdcb797.jpg</url>
      <title>DEV Community: Aniello Musella</title>
      <link>https://dev.to/animusna</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/animusna"/>
    <language>en</language>
    <item>
      <title>CouchDB: Backup strategies</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Fri, 22 Aug 2025 13:12:35 +0000</pubDate>
      <link>https://dev.to/animusna/couchdb-backup-strategies-2ji6</link>
      <guid>https://dev.to/animusna/couchdb-backup-strategies-2ji6</guid>
      <description>&lt;p&gt;&lt;strong&gt;CouchDB&lt;/strong&gt; is a good &lt;strong&gt;NoSQL&lt;/strong&gt; DBMS with some features that, according to me, are awesome like, for instance, the &lt;u&gt;multi-master synchronization &lt;/u&gt;and the &lt;u&gt;HTTP/JSON API to access to data&lt;/u&gt; (check my &lt;a href="https://dev.to/animusna/couchdb-offline-first-with-multi-master-synchronization-using-docker-and-docker-compose-293e"&gt;previous article&lt;/a&gt; about CouchDB where I talk about the multi-master sync using Docker).&lt;/p&gt;

&lt;p&gt;Today, I want to describe some of the possible strategies to back up a CouchDB database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manual strategy with tools
&lt;/h2&gt;

&lt;p&gt;You can use CouchDB's Built-in Backup Tools to back up and restore a database. These tools allow you to create backups of your databases and restore them when needed. You can find this tools on &lt;a href="https://github.com/IBM/couchbackup" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Following some examples:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;couchdbbackup &lt;span class="nt"&gt;-d&lt;/span&gt; my_database &lt;span class="nt"&gt;-o&lt;/span&gt; my_database_backup.couch &lt;span class="nt"&gt;--config&lt;/span&gt; couchdb_config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Where the file couchdb_config.json contains data to connect to the server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my_username"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my_password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:5984"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

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

&lt;/div&gt;



&lt;p&gt;To restore, you'll use 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;couchdbrestore &lt;span class="nt"&gt;-d&lt;/span&gt; my_database &lt;span class="nt"&gt;-i&lt;/span&gt; my_database_backup.couch &lt;span class="nt"&gt;--config&lt;/span&gt; couchdb_config.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Incremental backup with tools
&lt;/h3&gt;

&lt;p&gt;With these tools you can define an incremental backup like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;couchdbbackup &lt;span class="nt"&gt;-c&lt;/span&gt; couchdb_config.json &lt;span class="nt"&gt;--incremental&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;defining in the json configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my_username"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my_password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:5984"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"database"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my_database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my_incremental_backup.couch"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"incremental"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"since"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;last_backup_sequence&amp;gt;"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last backup sequence is an information that you get from database information. To get db information you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; GET http://localhost:5984/my_database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;getting somenthing like that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"db_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my_database"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"doc_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"doc_del_count"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"update_seq"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"purge_seq"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compact_running"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"disk_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2048000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2048000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"instance_start_time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"disk_format_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"committed_update_seq"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;150&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;update_seq&lt;/strong&gt; information indicates the sequence number of the last update made to the database, and this information will be used to make incremental backup.&lt;/p&gt;

&lt;p&gt;So when you perform an incremental backup, you specify the &lt;strong&gt;update_seq&lt;/strong&gt; value from your last backup. This tells the CouchDB backup tool to only include documents that have been added or modified since that sequence number.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Replication Strategy with CouchDB
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;I love this strategy&lt;/strong&gt; because &lt;u&gt;you use CouchDB to back up CouchDB&lt;/u&gt;.&lt;br&gt;
To do that, set up continuous replication to another CouchDB instance. This provides real-time backup and ensures that your data is always up-to-date in the backup instance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Snapshot Backups
&lt;/h2&gt;

&lt;p&gt;If you're using CouchDB as a cloud service or on a virtual machine, you can take snapshots of the entire disk. This can be a quick way to back up the entire database state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduled Backups
&lt;/h2&gt;

&lt;p&gt;You can schedule regular backups using &lt;strong&gt;cron jobs&lt;/strong&gt; or similar scheduling tools. Depending on your data change frequency, you'll define your schedule (daily, weekly, etc.).&lt;/p&gt;

&lt;h2&gt;
  
  
  Final considerations
&lt;/h2&gt;

&lt;p&gt;The best strategy it's mainly up to the architecture where CouchDB is running and the business requirements you must stick to.&lt;br&gt;
In general, once you have chosen a tailored backup strategy for your business case it's advised following best practices like &lt;em&gt;storing backups offsite&lt;/em&gt;, &lt;em&gt;testing your backups&lt;/em&gt;, &lt;em&gt;protecting your data with security and encryption&lt;/em&gt; and so on.&lt;/p&gt;

&lt;p&gt;Suggestions and corrections are welcome.&lt;/p&gt;

</description>
      <category>couchdb</category>
      <category>nosql</category>
      <category>database</category>
    </item>
    <item>
      <title>CouchDB: Offline-first multi-master synchronization using Docker and Docker-compose</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Tue, 05 Nov 2024 11:04:18 +0000</pubDate>
      <link>https://dev.to/animusna/couchdb-offline-first-with-multi-master-synchronization-using-docker-and-docker-compose-293e</link>
      <guid>https://dev.to/animusna/couchdb-offline-first-with-multi-master-synchronization-using-docker-and-docker-compose-293e</guid>
      <description>&lt;p&gt;In this post, I'll show how to simulate a multi-master synchronization with &lt;a href="https://couchdb.apache.org/" rel="noopener noreferrer"&gt;Apache CouchDB&lt;/a&gt; considering an off-line scenario. To reach this goal, I'll use &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker compose&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What should you know?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Apache CouchDB (basic)&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Docker Compose&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What do you need?
&lt;/h1&gt;

&lt;p&gt;Docker and Docker compose.&lt;/p&gt;

&lt;h1&gt;
  
  
  What's CouchDB
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://couchdb.apache.org/" rel="noopener noreferrer"&gt;CouchDB&lt;/a&gt; is a &lt;a href="https://en.wikipedia.org/wiki/NoSQL" rel="noopener noreferrer"&gt;NoSQL&lt;/a&gt; database &lt;a href="https://en.wikipedia.org/wiki/Document-oriented_database" rel="noopener noreferrer"&gt;document oriented&lt;/a&gt; using &lt;a href="https://it.wikipedia.org/wiki/JavaScript_Object_Notation" rel="noopener noreferrer"&gt;JSON format&lt;/a&gt; to store data. &lt;/p&gt;

&lt;p&gt;The CouchDB's main features are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single node&lt;/strong&gt; database.&lt;/li&gt;
&lt;li&gt;Possibility to be configured as a &lt;strong&gt;cluster&lt;/strong&gt; to increase the data availability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intuitive HTTP/JSON API&lt;/strong&gt; to access to data (e.g. http://&amp;lt;yourserver&amp;gt;:&amp;lt;yourport&amp;gt;/&amp;lt;dbname&amp;gt;/&amp;lt;document id&amp;gt;/)&lt;/li&gt;
&lt;li&gt;The use of &lt;a href="https://en.wikipedia.org/wiki/Multiversion_concurrency_control" rel="noopener noreferrer"&gt;multiversion concurrency control (MVCC)&lt;/a&gt; so the database file is not locked during writes (this helps performances). Conflicts are reported and managed at application level.&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://en.wikipedia.org/wiki/ACID" rel="noopener noreferrer"&gt;ACID&lt;/a&gt; properties at document level.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://en.wikipedia.org/wiki/Multi-master_replication" rel="noopener noreferrer"&gt;Multi master replication&lt;/a&gt; thanks to &lt;a href="https://docs.couchdb.org/en/stable/replication/protocol.html" rel="noopener noreferrer"&gt; CouchDB Replication Protocol&lt;/a&gt; able to synchronize JSON documents between 2 peers over HTTP/1.1 by using the public &lt;a href="https://docs.couchdb.org/en/stable/api/index.html#api" rel="noopener noreferrer"&gt;CouchDB REST API&lt;/a&gt; based on the Apache CouchDB &lt;a href="https://en.wikipedia.org/wiki/Multiversion_concurrency_control" rel="noopener noreferrer"&gt;MVCC&lt;/a&gt; Data model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline First Data Sync&lt;/strong&gt; thanks to its replication protocol, data are always available even in scenario of bad connectivity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Good platform scalability&lt;/strong&gt; from server to mobile (&lt;a href="https://pouchdb.com/" rel="noopener noreferrer"&gt;PouchDB&lt;/a&gt;) &lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What's a multi-master synchronization
&lt;/h1&gt;

&lt;p&gt;Quoting &lt;a href="https://en.wikipedia.org/wiki/Multi-master_replication" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Multi-master replication is a method of database replication which allows data to be stored by a group of computers, and updated by any member of the group. All members are responsive to client data queries. The multi-master replication system is responsible for propagating the data modifications made by each member to the rest of the group and resolving any conflicts that might arise between concurrent changes made by different members. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;CouchDB replication protocol&lt;/em&gt; lets to synchronize data between peers even in scenario of bad connectivity.&lt;/p&gt;

&lt;h1&gt;
  
  
  Multi-master synchronization: the scenario
&lt;/h1&gt;

&lt;p&gt;In my scenario, I want to use multi-master synchronization to replicate data between three installations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alpha
&lt;/li&gt;
&lt;li&gt;Beta &lt;/li&gt;
&lt;li&gt;Gamma &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this scenario, Alpha could be a database on main server (preferibly a cluster) and Beta and Gamma are edge installations with connectivity problems.&lt;/p&gt;

&lt;p&gt;The requirement is that all data must be replicated through all database istallations. Below it's shown the synchronization schema  schema.&lt;/p&gt;

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

&lt;p&gt;It's worth note, in this schema, that the synchronization is bidirectional:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alpha and Beta synchronize data bidirectionally&lt;/li&gt;
&lt;li&gt;Alpha and Gamma synchronize data bidirectionally&lt;/li&gt;
&lt;li&gt;Beta and Gamma don't need to be synchronized because they're already synchronized with Alpha, in this way I save network bandwidth.&lt;/li&gt;
&lt;li&gt;Nothing prevents to implement data replication between Beta and Gamma, but in my case I prefer to save network bandwidth (so it's a precise architectural choice).&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  POC
&lt;/h1&gt;

&lt;p&gt;Following I'll show all steps to simulate a multi-master synchronization. After tested the data replication, I'll consider an off-line scenario putting a database off-line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multi-master synchronization: Running all instances of CouchDB
&lt;/h2&gt;

&lt;p&gt;To implement the scenario described above, I'll use &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;Docker Compose&lt;/a&gt; to run a multi container application where each container represents respectively our Alpha, Beta and Gamma database installations.&lt;/p&gt;

&lt;p&gt;I'll use the &lt;a href="https://hub.docker.com/_/couchdb" rel="noopener noreferrer"&gt;official CouchDb docker image&lt;/a&gt; published on &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;DockerHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Following my &lt;strong&gt;docker-compose.yaml&lt;/strong&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3'
services:
  couchserveralfa:
    image: couchdb
    restart: always
    ports:
      - "5984:5984"
    environment:
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=A24cvmri
    volumes:
        - ./db/alpha:/opt/couchdb/data
        - ./config/alpha/local.ini:/opt/couchdb/etc/local.ini

  couchserverbeta:
    image: couchdb
    restart: always
    ports:
      - "5985:5984"
    environment:
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=9VQhWrfW
    volumes:
        - ./db/beta:/opt/couchdb/data
        - ./config/beta/local.ini:/opt/couchdb/etc/local.ini

  couchservergamma:
    image: couchdb
    restart: always
    ports:
      - "5986:5984"
    environment:
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=ouPFQ6mj
    volumes:
        - ./db/gamma:/opt/couchdb/data
        - ./config/gamma/local.ini:/opt/couchdb/etc/local.ini
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I map the default port &lt;strong&gt;5984&lt;/strong&gt; of CouchDB to host port &lt;em&gt;5984&lt;/em&gt; for &lt;em&gt;Alpha&lt;/em&gt;, &lt;em&gt;5985&lt;/em&gt; for &lt;em&gt;Beta&lt;/em&gt; and &lt;em&gt;5986&lt;/em&gt; for &lt;em&gt;Gamma&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this compose I use an'external configuration file &lt;strong&gt;local.ini&lt;/strong&gt;  for each installation  to set this configuration (source &lt;a href="https://stackoverflow.com/questions/58469486/error-could-not-resolve-http-any5984-verifytestdb-in-couchdb-docker-containconfiguration" rel="noopener noreferrer"&gt;stack over flow&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[chttpd]
port = 5984
bind_address = 0.0.0.0    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I've mapped on the host file system (in the folder ./db/[alpha|beta|gamma]/) each database.&lt;/p&gt;

&lt;p&gt;Now we can start the databases:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animus:~$docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multi-master synchronization: Creating databases to be synchronized
&lt;/h2&gt;

&lt;p&gt;Using &lt;a href="https://couchdb.apache.org/fauxton-visual-guide/index.html" rel="noopener noreferrer"&gt;Flauxton&lt;/a&gt; login (as admin) in each node, accessing to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://localhost:5984/_utils/" rel="noopener noreferrer"&gt;http://localhost:5984/_utils/&lt;/a&gt; for &lt;strong&gt;Alpha&lt;/strong&gt; installation&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://localhost:5985/_utils/" rel="noopener noreferrer"&gt;http://localhost:5985/_utils/&lt;/a&gt; for &lt;strong&gt;Beta&lt;/strong&gt; installation&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://localhost:5986/_utils/" rel="noopener noreferrer"&gt;http://localhost:5986/_utils/&lt;/a&gt; for &lt;strong&gt;Gamma&lt;/strong&gt; installation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For each installation, Select &lt;strong&gt;Databases&lt;/strong&gt; from side menu and then &lt;strong&gt;Create Database&lt;/strong&gt;, type the name of the database (in my case &lt;strong&gt;mydb&lt;/strong&gt;) and click on create button like shown below:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Multi-master synchronization: Creating replication
&lt;/h2&gt;

&lt;p&gt;Now it's the moment to create replication. &lt;br&gt;
Select &lt;strong&gt;Replication&lt;/strong&gt; side menu and then click on &lt;strong&gt;New Replication&lt;/strong&gt; button.&lt;/p&gt;

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

&lt;p&gt;In this page we can create the replications.&lt;/p&gt;

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

&lt;p&gt;In CouchDB replications are documents belonging to &lt;strong&gt;_replicator&lt;/strong&gt; DB, so when you click &lt;strong&gt;Start Replication&lt;/strong&gt; you create a new document.&lt;/p&gt;
&lt;h3&gt;
  
  
  Multi-master synchronization: Creating replications on Database Alpha
&lt;/h3&gt;

&lt;p&gt;On DB &lt;strong&gt;Alpha&lt;/strong&gt; (port 5984) we create two continuos replication:&lt;/p&gt;

&lt;p&gt;One toward &lt;strong&gt;Beta&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;{
  "_id": "69b5d15c85f1e8e5352136a2ce00457f",
  "_rev": "1-87b5f963a45b2d8df14eb10a3cdbd1f0",
  "user_ctx": {
    "name": "admin",
    "roles": [
      "_admin",
      "_reader",
      "_writer"
    ]
  },
  "source": {
    "url": "http://localhost:5984/mydb",
    "headers": {
      "Authorization": "Basic YWRtaW46MTIz"
    }
  },
  "target": {
    "url": "http://&amp;lt;YOUR IP ADDRESS&amp;gt;:5986/mydb",
    "headers": {
      "Authorization": "Basic YWRtaW46MTIz"
    }
  },
  "create_target": false,
  "continuous": true,
  "owner": "admin"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One toward &lt;strong&gt;Gamma&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;{
  "_id": "b15782ac94b2277c570b8689ab000d67",
  "_rev": "1-4912109dc6748874144aeef24ec23f20",
  "user_ctx": {
    "name": "admin",
    "roles": [
      "_admin",
      "_reader",
      "_writer"
    ]
  },
  "source": {
    "url": "http://localhost:5984/mydb",
    "headers": {
      "Authorization": "Basic YWRtaW46MTIz"
    }
  },
  "target": {
    "url": "http://&amp;lt;YOUR IP ADDRESS&amp;gt;:5985/mydb",
    "headers": {
      "Authorization": "Basic YWRtaW46MTIz"
    }
  },
  "create_target": false,
  "continuous": true,
  "owner": "admin"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Multi-master synchronization: Creating replications on Database Beta
&lt;/h3&gt;

&lt;p&gt;On DB &lt;strong&gt;Beta&lt;/strong&gt; (port 5985) we create one continuos replication toward Alpha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "_id": "b45d1f6f186500eaa926b6d84d000507",
  "_rev": "4-6884dcb72b7132562e10d9a83c59936c",
  "user_ctx": {
    "name": "admin",
    "roles": [
      "_admin",
      "_reader",
      "_writer"
    ]
  },
  "source": {
    "url": "http://localhost:5984/mydb",
    "headers": {
      "Authorization": "Basic YWRtaW46MTIz"
    }
  },
  "target": {
    "url": "http://&amp;lt;YOUR IP ADDRESS&amp;gt;:5984/mydb",
    "headers": {
      "Authorization": "Basic YWRtaW46MTIz"
    }
  },
  "create_target": false,
  "continuous": true,
  "owner": "admin"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note, even if we have mapped database Beta on host port 5895, the native port of the service remains 5894.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-master synchronization: Creating replications on Database Gamma
&lt;/h3&gt;

&lt;p&gt;On DB &lt;strong&gt;Gamma&lt;/strong&gt; (port 5986) we create one continuous replication toward Alpha:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "_id": "b45d1f6f186500eaa926b6d84d000507",
  "_rev": "4-6884dcb72b7132562e10d9a83c59936c",
  "user_ctx": {
    "name": "admin",
    "roles": [
      "_admin",
      "_reader",
      "_writer"
    ]
  },
  "source": {
    "url": "http://localhost:5984/mydb",
    "headers": {
      "Authorization": "Basic YWRtaW46MTIz"
    }
  },
  "target": {
    "url": "http://&amp;lt;YOUR IP ADDRESS&amp;gt;:5984/mydb",
    "headers": {
      "Authorization": "Basic YWRtaW46MTIz"
    }
  },
  "create_target": false,
  "continuous": true,
  "owner": "admin"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note, even if we have mapped database Gamma on host port 5896, the native port of the service remains 5894.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-master synchronization: Creating documents
&lt;/h3&gt;

&lt;p&gt;Now we're ready to create new documents. &lt;/p&gt;

&lt;p&gt;Choose a database (alpha, beta or gamma) and go to side menu bar, select &lt;strong&gt;Databases&lt;/strong&gt;, then select &lt;strong&gt;Create Document&lt;/strong&gt;. Compose your document and then confirm. &lt;/p&gt;

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

&lt;p&gt;Wait few seconds and the document you've just created is sent to other databases (here we go!).&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-master synchronization: Creating documents off-line
&lt;/h3&gt;

&lt;p&gt;I turn off database Alpha and Gamma running the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animus:~$docker kill couchdb_couchserveralfa_1 &amp;amp;&amp;amp; docker kill couchdb_couchserverbeta_1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On database gamma I create the document while the other databases are off-line.&lt;/p&gt;

&lt;p&gt;After the creation of the new document I turn on the other databases running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animus:~$docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait few seconds and the document you've just created on Gamma database is sent while the other databases were off-line. So we've just proved that the synchonization works when they return on-line (here we go!).&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;In this article, I've shown how to simulate the multi-master synchronization of CouchDB and how to simulate an off-line scenario where I show that data keep on to be available for local operations and then be synchronized when the database returns on-line.&lt;br&gt;
In these scenarios, CouchDB turned out a good solution.&lt;br&gt;
Suggestions and corrections are welcome.&lt;/p&gt;

</description>
      <category>couchdb</category>
      <category>docker</category>
      <category>nosql</category>
      <category>database</category>
    </item>
    <item>
      <title>MongoDb Atlas: manual backup and restore data</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Wed, 16 Oct 2024 16:34:38 +0000</pubDate>
      <link>https://dev.to/animusna/mongodb-atlas-manual-backup-and-restore-data-45ja</link>
      <guid>https://dev.to/animusna/mongodb-atlas-manual-backup-and-restore-data-45ja</guid>
      <description>&lt;p&gt;In this post, I'll show how to back up and restore data from a database &lt;a href="https://it.wikipedia.org/wiki/MongoDB" rel="noopener noreferrer"&gt;MongoDB&lt;/a&gt; hosted on &lt;a href="https://www.mongodb.com/it-it/atlas" rel="noopener noreferrer"&gt;MongoDB Atlas&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What should you know?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of MongoDB&lt;/li&gt;
&lt;li&gt;Basic knowledge of Bash Scripts&lt;/li&gt;
&lt;li&gt;Basic knowledge of &lt;a href="https://www.mongodb.com/docs/database-tools/" rel="noopener noreferrer"&gt;MongoDB Tools&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What do you need?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Bash shell&lt;/li&gt;
&lt;li&gt;MongoDB Atlas cluster with a DB deployed&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/database-tools/mongodump/#mongodb-binary-bin.mongodump" rel="noopener noreferrer"&gt;mongodump&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.mongodb.com/docs/database-tools/mongorestore/" rel="noopener noreferrer"&gt;mongorestore&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Backup data
&lt;/h1&gt;

&lt;p&gt;Download and install &lt;a href="https://www.mongodb.com/docs/database-tools/mongodump/#mongodb-binary-bin.mongodump" rel="noopener noreferrer"&gt;mongodump&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;mongodump&lt;/strong&gt; is, quoting from the official site, "&lt;em&gt;a utility that creates a binary export of a database's contents...&lt;/em&gt;".&lt;/p&gt;

&lt;p&gt;Before to use this tool you must get the db connection string, and depending on cluster structure you have to compose your connection string.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://www.mongodb.com/docs/database-tools/mongodump/mongodump-compatibility-and-installation/" rel="noopener noreferrer"&gt;the official guide&lt;/a&gt; they explain how to compose the connection string in case you have to connect to &lt;strong&gt;one instance&lt;/strong&gt;, &lt;strong&gt;replica set&lt;/strong&gt; and &lt;strong&gt;sharded cluster&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In my case is a &lt;strong&gt;replica set&lt;/strong&gt; and my connection string is something like shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mongodb://&amp;lt;user&amp;gt;:&amp;lt;password&amp;gt;@mycluster-00-00.xyzw.mongodb.net:27017,@mycluster-00-01.xyzw.mongodb.net:27017,@mycluster-00-02.xyzw.mongodb.net:27017
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, once we prepared the connection string, we are ready to back up data of our database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animus:~$ mongodump \
--uri="mongodb://mongodb://&amp;lt;user&amp;gt;:&amp;lt;password&amp;gt;@mycluster-00-00.xyzw.mongodb.net:27017,@mycluster-00-01.xyzw.mongodb.net:27017,@mycluster-00-02.xyzw.mongodb.net:27017" \
--ssl \
--authenticationDatabase=&amp;lt;db user&amp;gt; \
--db=&amp;lt;database name&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The command will produce a folder &lt;strong&gt;dump&lt;/strong&gt; with all data backup.&lt;/p&gt;

&lt;h1&gt;
  
  
  Restore data
&lt;/h1&gt;

&lt;p&gt;Download and install &lt;a href="https://www.mongodb.com/docs/database-tools/mongorestore/mongorestore-compatibility-and-installation/" rel="noopener noreferrer"&gt;mongorestore&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;mongorestore&lt;/strong&gt; is, quoting from official site, "&lt;em&gt;a program that loads data from either a binary database dump created by &lt;strong&gt;mongodump&lt;/strong&gt; or the standard input into a &lt;strong&gt;mongod&lt;/strong&gt; or &lt;strong&gt;mongos&lt;/strong&gt; instance&lt;/em&gt;".&lt;/p&gt;

&lt;p&gt;Before to use this tool we need the connection string to the destination cluster and the considerations made for the dump are valid for the restore too.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animus:~$ mongorestore \
--uri="mongodb://mongodb://&amp;lt;user&amp;gt;:&amp;lt;password&amp;gt;@mycluster-00-00.xyzw.mongodb.net:27017,@mycluster-00-01.xyzw.mongodb.net:27017,@mycluster-00-02.xyzw.mongodb.net:27017" \
--ssl \
--authenticationDatabase=&amp;lt;db user&amp;gt; \
--db=&amp;lt;database name&amp;gt; \
&amp;lt;database dump folder&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the command run is completed, you'll have the database completely restored.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;MongoDB Atlas&lt;/strong&gt; is a cloud service and, as such, you can count on better backup and restore data strategies able &lt;em&gt;to not impact on the normal activity of the service&lt;/em&gt;. The manual backup and restore could be useful in dev or test scenario and when the dimension of data to copy is not so huge. Take in mind the use of mongodump and mongorestore in production could have an impact on the normal activity of the service.&lt;/p&gt;

</description>
      <category>mongodb</category>
      <category>nosql</category>
      <category>db</category>
    </item>
    <item>
      <title>React: stale closure</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Mon, 19 Aug 2024 14:28:46 +0000</pubDate>
      <link>https://dev.to/animusna/react-stale-closure-81a</link>
      <guid>https://dev.to/animusna/react-stale-closure-81a</guid>
      <description>&lt;p&gt;In this post, I'll show how to create a closure in a &lt;a href="https://react.dev/reference/react/useState" rel="noopener noreferrer"&gt;useState&lt;/a&gt; hook React app.&lt;/p&gt;

&lt;p&gt;I'll not explain what a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures" rel="noopener noreferrer"&gt;closure&lt;/a&gt; is, because there are many resources about this topic and I don't want to be repetitive. I advise the reading of &lt;a href="https://dev.to/imranabdulmalik/mastering-closures-in-javascript-a-comprehensive-guide-4ja8"&gt;this article&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/imranabdulmalik"&gt;@imranabdulmalik&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In short, a &lt;strong&gt;closure&lt;/strong&gt; is (from Mozilla):&lt;/p&gt;

&lt;p&gt;&lt;em&gt;...the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment). In other words, a closure gives you access to an outer function's scope from an inner function. In JavaScript, closures are created every time a function is created, at function creation time&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Just in case you're not familiar with the term &lt;strong&gt;lexical environment,&lt;/strong&gt; you can read &lt;a href="https://dev.to/soumyadey/understanding-lexical-scope-closures-in-javascript-229b"&gt;this article&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/soumyadey"&gt;@soumyadey&lt;/a&gt; or alternatively &lt;a href="https://www.freecodecamp.org/news/lexical-scope-in-javascript/" rel="noopener noreferrer"&gt;this one&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;In a React application, you can create accidentally a closure of a variable belonging to the component state created with &lt;a href="https://react.dev/reference/react/useState" rel="noopener noreferrer"&gt;useState hook&lt;/a&gt;. When this happens, you're facing a &lt;strong&gt;stale closure&lt;/strong&gt; problem, that is to say, when you refer to an old value of the state that in the meantime it's changed, and so it's not more relevant.&lt;/p&gt;

&lt;h1&gt;
  
  
  POC
&lt;/h1&gt;

&lt;p&gt;I've created a Demo React application which the main goal is to increment a counter (belonging to the state) that can be closed in a closure in the callback of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/setTimeout" rel="noopener noreferrer"&gt;setTimeout&lt;/a&gt; method.&lt;/p&gt;

&lt;p&gt;In short, this app can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Show the value of the counter&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Increment by 1 the counter&lt;/em&gt; &lt;/li&gt;
&lt;li&gt;&lt;em&gt;Start a timer to increment the counter by 1 after five seconds.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Increment by 10 the counter&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the following picture, it's shown the initial UI state of the app, with counter to zero.&lt;/p&gt;

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

&lt;p&gt;We'll simulate the &lt;u&gt;closure of the counter&lt;/u&gt; in three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Incrementing by 1 the counter&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawnyq6jj057p7624xgw4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fawnyq6jj057p7624xgw4.png" alt="The count has been incremented by 1" width="718" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Starting the timer to increment by 1 after five seconds&lt;/li&gt;
&lt;/ol&gt;

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

&lt;ul&gt;
&lt;li&gt;Incrementing by 10 before the timeout triggers
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0zz96a5madn3xz9mtgxw.png" alt="The count has been incremented by 10" width="717" height="418"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After 5 seconds, the value of the counter is 2.&lt;/p&gt;

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

&lt;p&gt;&lt;u&gt;The expected value of the counter should be &lt;em&gt;12&lt;/em&gt;&lt;/u&gt;, but we get &lt;strong&gt;2&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;The reason why this happens it's because we've created a &lt;strong&gt;closure of the counter&lt;/strong&gt; in the callback passed to &lt;strong&gt;setTimeout&lt;/strong&gt; and when the timeout is triggered we set the counter starting from its old value (that was 1).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setTimeout(() =&amp;gt; {
        setLogs((l) =&amp;gt; [...l, `You closed counter with value: ${counter}\n and now I'll increment by one. Check the state`])
        setTimeoutInProgress(false)
        setStartTimeout(false)
        setCounter(counter + 1)
        setLogs((l) =&amp;gt; [...l, `Did you create a closure of counter?`])

      }, timeOutInSeconds * 1000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following the full code of the app component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function App() {
  const [counter, setCounter] = useState&amp;lt;number&amp;gt;(0)
  const timeOutInSeconds: number = 5
  const [startTimeout, setStartTimeout] = useState&amp;lt;boolean&amp;gt;(false)
  const [timeoutInProgress, setTimeoutInProgress] = useState&amp;lt;boolean&amp;gt;(false)
  const [logs, setLogs] = useState&amp;lt;Array&amp;lt;string&amp;gt;&amp;gt;([])

  useEffect(() =&amp;gt; {
    if (startTimeout &amp;amp;&amp;amp; !timeoutInProgress) {
      setTimeoutInProgress(true)
      setLogs((l) =&amp;gt; [...l, `Timeout scheduled in ${timeOutInSeconds} seconds`])
      setTimeout(() =&amp;gt; {
        setLogs((l) =&amp;gt; [...l, `You closed counter with value: ${counter}\n and now I'll increment by one. Check the state`])
        setTimeoutInProgress(false)
        setStartTimeout(false)
        setCounter(counter + 1)
        setLogs((l) =&amp;gt; [...l, `Did you create a closure of counter?`])

      }, timeOutInSeconds * 1000);
    }
  }, [counter, startTimeout, timeoutInProgress])

  function renderLogs(): React.ReactNode {
    const listItems = logs.map((log, index) =&amp;gt;
      &amp;lt;li key={index}&amp;gt;{log}&amp;lt;/li&amp;gt;
    );
    return &amp;lt;ul&amp;gt;{listItems}&amp;lt;/ul&amp;gt;;
  }

  function updateCounter(value: number) {
    setCounter(value)
    setLogs([...logs, `The value of counter is now ${value}`])
  }

  function reset() {
    setCounter(0)
    setLogs(["reset done!"])
  }

  return (

    &amp;lt;div className="App"&amp;gt;
      &amp;lt;h1&amp;gt;Closure demo&amp;lt;/h1&amp;gt;
      &amp;lt;hr /&amp;gt;
      &amp;lt;h3&amp;gt;Counter value: {counter}&amp;lt;/h3&amp;gt;&amp;lt;button onClick={reset}&amp;gt;reset&amp;lt;/button&amp;gt;
      &amp;lt;hr /&amp;gt;
      &amp;lt;h3&amp;gt;Follow the istructions to create a &amp;lt;i&amp;gt;closure&amp;lt;/i&amp;gt; of the state variable counter&amp;lt;/h3&amp;gt;
      &amp;lt;ol type='1' className=''&amp;gt;
        &amp;lt;li&amp;gt;Set the counter to preferred value &amp;lt;button onClick={() =&amp;gt; updateCounter(counter + 1)}&amp;gt;+1&amp;lt;/button&amp;gt; &amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;Start a timeout and wait for {timeOutInSeconds} to increment the counter (current value is {counter}) &amp;lt;button onClick={() =&amp;gt; setStartTimeout(true)}&amp;gt;START&amp;lt;/button&amp;gt; &amp;lt;/li&amp;gt;
        &amp;lt;li&amp;gt;Increment by 10 the counter before the timeout  &amp;lt;button onClick={() =&amp;gt; updateCounter(counter + 10)}&amp;gt;+10&amp;lt;/button&amp;gt; &amp;lt;/li&amp;gt;
      &amp;lt;/ol&amp;gt;
      &amp;lt;hr /&amp;gt;
      {
        renderLogs()
      }
    &amp;lt;/div &amp;gt;
  );
}

export default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;The solution is based on the use of &lt;a href="https://react.dev/reference/react/useRef" rel="noopener noreferrer"&gt;useRef hook&lt;/a&gt; that lets you reference a value that’s not needed for rendering.&lt;/p&gt;

&lt;p&gt;So we add to the App component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const currentCounter = useRef(counter)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we'll modify the callback of setTimeout like shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setTimeout(() =&amp;gt; {
        setLogs((l) =&amp;gt; [...l, `You closed counter with value: ${currentCounter.current}\n and now I'll increment by one. Check the state`])
        setTimeoutInProgress(false)
        setStartTimeout(false)
        setCounter(currentCounter.current + 1)
        setLogs((l) =&amp;gt; [...l, `Did you create a closure of counter?`])

      }, timeOutInSeconds * 1000);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our callback needs to read the counter value because we log the current value before to increment it. &lt;/p&gt;

&lt;p&gt;In case, you don't need to read the value, you can avoid the closure of the counter just using the &lt;strong&gt;functional notation&lt;/strong&gt; to update the counter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;setCounter(c =&amp;gt; c + 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Credits
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Dmitri Pavlutin &lt;a href="https://dmitripavlutin.com/react-hooks-stale-closures/" rel="noopener noreferrer"&gt;Be Aware of Stale Closures when Using React Hooks&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Imran Abdulmalik &lt;a href="https://dev.to/imranabdulmalik/mastering-closures-in-javascript-a-comprehensive-guide-4ja8"&gt;Mastering Closures in JavaScript: A Comprehensive Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Keyur Paralkar &lt;a href="https://www.freecodecamp.org/news/lexical-scope-in-javascript/" rel="noopener noreferrer"&gt;Lexical Scope in JavaScript – Beginner's Guide&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Souvik Paul &lt;a href="https://javascript.plainenglish.io/stale-closures-in-react-afb0dda37f0b" rel="noopener noreferrer"&gt;Stale Closures in React&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Soumya Dey &lt;a href="https://dev.to/soumyadey/understanding-lexical-scope-closures-in-javascript-229b"&gt;Understanding Lexical Scope &amp;amp; Closures in JavaScript &lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Subash Mahapatra &lt;a href="https://stackoverflow.com/questions/62806541/how-to-solve-the-react-hook-closure-issue" rel="noopener noreferrer"&gt;stackoverflow&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>coding</category>
      <category>node</category>
    </item>
    <item>
      <title>Log rotation with Python</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Wed, 25 Oct 2023 18:11:21 +0000</pubDate>
      <link>https://dev.to/animusna/log-rotation-with-python-2ife</link>
      <guid>https://dev.to/animusna/log-rotation-with-python-2ife</guid>
      <description>&lt;p&gt;In this post, I show how to implement &lt;a href="https://en.wikipedia.org/wiki/Log_rotation" rel="noopener noreferrer"&gt;log rotation&lt;/a&gt; in a Python project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's log rotation?
&lt;/h2&gt;

&lt;p&gt;From &lt;a href="https://en.wikipedia.org/wiki/Log_rotation" rel="noopener noreferrer"&gt;Wikipedia&lt;/a&gt;: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In information technology, log rotation is an automated process used in system administration in which log files are compressed, moved (archived), renamed or deleted once they are too old or too big (there can be other metrics that can apply here). New incoming log data is directed into a new, fresh file (at the same location)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, it's important to consider log rotation specially in that systems that produce a great quantity of log messages.&lt;/p&gt;

&lt;p&gt;There are different criteria of log rotation and in this post I'll focus on timed log rotation and file size rotation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we implement logging in Python?
&lt;/h2&gt;

&lt;p&gt;Super easy, just using the &lt;strong&gt;logging module&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The logging module offers a default logger named "root". This logger allows you to get started with no configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import logging
logging.info('This is an info message')
logging.warning('This is a warning message')
logging.error('This is an error message')
logging.critical('This is a critical message')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This module permit a lot of customizations like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logging severity level&lt;/li&gt;
&lt;li&gt;File name&lt;/li&gt;
&lt;li&gt;Log format&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can create a custom logger using the class &lt;strong&gt;Logger,&lt;/strong&gt; defining a &lt;strong&gt;basic configuration&lt;/strong&gt; (&lt;em&gt;date format&lt;/em&gt;, &lt;em&gt;log format&lt;/em&gt;, etc.).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  logging.basicConfig(
        format='%(asctime)s %(levelname)s %(message)s',
        level=logging.DEBUG,
        datefmt='%m/%d/%Y %I:%M:%S %p',
    )

    # Log formatter definition
    log_formatter = logging.Formatter(fmt=' %(asctime)s %(levelname)s %(message)s')

    # Getting the logger
    logger = logging.getLogger('my-logger')

    # Using the logger
    logging.debug('This is a debug message')
    logging.info('This is an info message')
    logging.warning('This is a warning message')
    logging.error('This is an error message')
    logging.critical('This is a critical message')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To implement different ways to log information, Python uses &lt;strong&gt;log handlers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;log handlers&lt;/strong&gt; are components that effectively writes logs, and they give you the opportunity of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Display logs in the console (StreamHandler)&lt;/li&gt;
&lt;li&gt;Write logs on files (FileHandler)&lt;/li&gt;
&lt;li&gt;Write logs on files with log rotation based on file size criteria (RotatingFileHandler)&lt;/li&gt;
&lt;li&gt;Write logs on files with log rotation based on time conditions (TimedRotatingFileHandler)&lt;/li&gt;
&lt;li&gt;Sending logs via SMTP (SMTPHandler)&lt;/li&gt;
&lt;li&gt;etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can create your custom handler or extend a pre-existing handler. &lt;/p&gt;

&lt;h2&gt;
  
  
  File Logging with Python
&lt;/h2&gt;

&lt;p&gt;To implement file logging, we'll use the &lt;strong&gt;FileHandler&lt;/strong&gt;, a handler able to write logs to the file system. &lt;br&gt;
Below is shown how to define this handler using the same basic configuration defined previously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # File handler definition
    fh: logging.FileHandler = logging.FileHandler(
        filename=f'./logs/my-app-file.log',
        mode='a'
    )

    # Setting the formatter for the handler
    fh.setFormatter(log_formatter)

    # Setting the severity level for the handler
    fh.setLevel(logging.INFO)

    # Adding handler to the logger
    logger.addHandler(fh)

    #Trying the handler using the handler
    logger.info('This log is an info message')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This handler simply writes log messages to a file named my-app-file.log.&lt;/p&gt;

&lt;h2&gt;
  
  
  Log rotation with Python
&lt;/h2&gt;

&lt;h3&gt;
  
  
  File size log rotation
&lt;/h3&gt;

&lt;p&gt;To implement logging rotation based on the size of the file, we'll use the &lt;strong&gt;RotatingFileHandler&lt;/strong&gt;. This handler is used to write logs on the file system and to trigger a rotation when a specific size of the file is reached. &lt;br&gt;
Below is shown how to define this handler using the same basic configuration defined previously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Rotation file handler definition
    rfh: RotatingFileHandler = RotatingFileHandler (
        filename=f'./logs/my-app.log',
        maxBytes=100,
        backupCount=5
    )

    # Setting the formatter for the handler
    rfh.setFormatter(log_formatter)

    # Setting the severity level for the handler
    rfh.setLevel(logging.INFO)

    # Adding handler to the logger    
    logger.addHandler(rfh)

    # Trying the handler using the handler
    logger.info('This log is an info message')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we've set a max dimension of 100 bytes and a backup count of 5 log files (this means that we keep at most 5 files from the log history).&lt;/p&gt;

&lt;p&gt;A result of this rotation after writing more than 1024 bytes could be something like shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-app.log
my-app.log.1
my-app.log.2
my-app.log.3
my-app.log.4
my-app.log.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Timed log rotation with Python
&lt;/h3&gt;

&lt;p&gt;To implement file rotation logging based on time event, we'll use the &lt;strong&gt;TimedRotatingFileHandler&lt;/strong&gt; that is the handler used to write logs on the file system and trigger a rotation when a time condition is satisfied.&lt;br&gt;
Below is shown how to define this handler using the same basic configuration of the previous examples.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    rth: TimedRotatingFileHandler = TimedRotatingFileHandler(
        filename=f'./logs/{log_file_prefix}.log',
        backupCount=5,
        when='midnight',
    )
    rth.setFormatter(log_formatter)
    rth.setLevel(logging.INFO)
    rth.namer = lambda name: name.replace(".log", "") + ".log"


    logger.addHandler(rth)
    logger.info('This log is an info message')
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we've set a daily rotation triggered each midnight and a backup count of 5 files. &lt;/p&gt;

&lt;p&gt;A result of this rotation after 5 days could be something like shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;my-app.log
my-app.2023-10-12.log
my-app.2023-10-11.log
my-app.2023-10-10.log
my-app.2023-10-09.log
my-app.2023-10-08.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this handler, we've defined a &lt;em&gt;namer&lt;/em&gt; with a lambda function that has the goal to preserve the extension of the log files. This &lt;em&gt;namer&lt;/em&gt; get in on the action when a rotation happens.&lt;/p&gt;

&lt;h4&gt;
  
  
  Custom File timed log rotation with Python
&lt;/h4&gt;

&lt;p&gt;It's possible to create the own log handler extending a pre-existing handler. For instance, we can extend the &lt;strong&gt;TimedRotatingFileHandler&lt;/strong&gt; class in a way to introduce, for each log message emission, a check about the presence of the file. In this way, if someone or something deletes the file, the handler is able to create it again, and we don't miss further log messages.&lt;/p&gt;

&lt;p&gt;Let's create the class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class TimedRotatingFileHandlerWithFileCheck(TimedRotatingFileHandler):
    """
    Handler for logging to a file, rotating the log file at certain timed
    intervals. This handler based on TimedRotatingFileHandler offers a file 
    presence check for each log emission.
    """
    def __init__(self, filename, when='h', interval=1, backupCount=0,
                 encoding=None, delay=False, utc=False, atTime=None,
                 errors=None):
        super().__init__(filename, when, interval, backupCount, encoding, delay, utc, atTime, errors)

    def emit(self, record):
        if not os.path.isfile(self.baseFilename):
            os.mknod(self.baseFilename)
        super(TimedRotatingFileHandlerWithFileCheck, self).emit(record)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this version, before to emit a log, we check the presence of the file.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;In Python, logging is super easy! The &lt;strong&gt;logging module&lt;/strong&gt; offers a lot of possibilities to customize and implement the strategy more suitable for you. The presence of a lot of handlers and the possibility to have a high level of customization makes this module very useful.&lt;br&gt;
In my opinion, having a good and balanced logging system is a must for each system or application.&lt;/p&gt;

&lt;p&gt;Suggestions and corrections are welcome.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://realpython.com/python-logging/" rel="noopener noreferrer"&gt;Abhinav Ajitsaria from realpython.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.toptal.com/python/in-depth-python-logging" rel="noopener noreferrer"&gt;Son Nguyen Kim from toptal.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>logging</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Dev Container for React Native with Expo</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Fri, 22 Sep 2023 16:49:30 +0000</pubDate>
      <link>https://dev.to/animusna/dev-container-for-react-native-with-expo-f7j</link>
      <guid>https://dev.to/animusna/dev-container-for-react-native-with-expo-f7j</guid>
      <description>&lt;p&gt;In this post, I'll show how to create a &lt;a href="https://containers.dev/" rel="noopener noreferrer"&gt;Development container&lt;/a&gt; (aka &lt;strong&gt;dev container&lt;/strong&gt;) to use it to develop a &lt;a href="https://reactnative.dev/" rel="noopener noreferrer"&gt;React Native&lt;/a&gt; app with &lt;a href="https://expo.dev/" rel="noopener noreferrer"&gt;Expo&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What should you know?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of Docker&lt;/li&gt;
&lt;li&gt;Basic knowledge of React Native&lt;/li&gt;
&lt;li&gt;Basic knowledge of Expo&lt;/li&gt;
&lt;li&gt;Basic knowledge of Bash&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What do you need?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; installed.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt; installed.&lt;/li&gt;
&lt;li&gt;A Linux box with bash (for Windows users, you can use WSL).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://expo.dev/client" rel="noopener noreferrer"&gt;Expo client&lt;/a&gt; on your phone.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Why dev containers?
&lt;/h1&gt;

&lt;p&gt;In short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You prepare the dev environment one time and every developer can use it.&lt;/li&gt;
&lt;li&gt;Dev containers are always ready when you need it.&lt;/li&gt;
&lt;li&gt;Dev containers are always consistent for every developer.&lt;/li&gt;
&lt;li&gt;Dev containers are fully integrated with popular IDE like Visual Studio Code, PyCharm and others.&lt;/li&gt;
&lt;li&gt;You can use them remotely&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to go into the details, check the following link from &lt;a class="mentioned-user" href="https://dev.to/blackgirlbytes"&gt;@blackgirlbytes&lt;/a&gt; &lt;a href="https://dev.to/github/why-are-people-developing-inside-containers-38o6"&gt;Why are people developing inside containers? &lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Dev Container preparation
&lt;/h1&gt;

&lt;p&gt;Let's prepare the working directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;animus@devto:~$ mkdir my-app
animus@devto:~$ cd my-app
animus@devto:~$ git init -b main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start Visual Studio Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;animus@devto:~$ code .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Type &lt;strong&gt;CTRL+SHIFT+P&lt;/strong&gt; to run the &lt;strong&gt;Command Palette&lt;/strong&gt; and when ready type &lt;strong&gt;Dev Containers: Add Dev Container configuration files&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Choose the dev container &lt;strong&gt;Node.js &amp;amp; TypeScript&lt;/strong&gt; container like shown below.&lt;/p&gt;

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

&lt;p&gt;Choose default image and don't select any features.&lt;/p&gt;

&lt;p&gt;After saved the dev container configuration,   you should see a folder named &lt;strong&gt;./devcontainer&lt;/strong&gt; with a JSON file &lt;strong&gt;devcontainer.json&lt;/strong&gt; containing the default definition of the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
    "name": "Node.js &amp;amp; TypeScript",
    // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
    "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye"

    // Features to add to the dev container. More info: https://containers.dev/features.
    // "features": {},

    // Use 'forwardPorts' to make a list of ports inside the container available locally.
    // "forwardPorts": [],

    // Use 'postCreateCommand' to run commands after the container is created.
    // "postCreateCommand": "yarn install",

    // Configure tool-specific properties.
    // "customizations": {},

    // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
    // "remoteUser": "root"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Edit this file like shown below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node
{
    "name": "Node.js &amp;amp; TypeScript",
    // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
    "image": "mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye",

    // Features to add to the dev container. More info: https://containers.dev/features.
    // "features": {},

    // Use 'forwardPorts' to make a list of ports inside the container available locally.
    "forwardPorts": [8081],
    "initializeCommand": "bash .devcontainer/initializeCommand.sh",
    // Use 'postCreateCommand' to run commands after the container is created.
    "postCreateCommand": "bash .devcontainer/postCreateCommand.sh",

    // Configure tool-specific properties.
    // "customizations": {},

    // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
    // "remoteUser": "root",

    "runArgs": ["-p=8081:8081", "--env-file", ".devcontainer/.env"]

}

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

&lt;/div&gt;



&lt;p&gt;In this new version of this file, I've added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;initializeCommand&lt;/strong&gt; This section permit to execute a command before the build of the container. I've used this command to execute a script to generate a file of &lt;u&gt;environment variables&lt;/u&gt; to use them in the container (the script will be described in the next chapter).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  bash .devcontainer/initializeCommand.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;postCreateCommand&lt;/strong&gt; This section permit to execute a command after the build of the container.
I've used this command to execute a script to install &lt;a href="https://expo.dev/" rel="noopener noreferrer"&gt;Expo&lt;/a&gt; and other dependencies like &lt;a href="https://facebook.github.io/watchman/" rel="noopener noreferrer"&gt;watchman&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  bash .devcontainer/postCreateCommand.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;forwardPorts&lt;/strong&gt; I've exposed the port number 8081 to permit the Expo client to access to your app.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  "forwardPorts": [8081]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;runArgs&lt;/strong&gt; I've defined an argument to run the container:

&lt;ul&gt;
&lt;li&gt;port binding with the host&lt;/li&gt;
&lt;li&gt;environment file (generated in the initialize command script)
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "runArgs": ["-p=8081:8081", "--env-file", ".devcontainer/.env"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The initialize command script
&lt;/h2&gt;

&lt;p&gt;The initialize command script &lt;strong&gt;initializeCommand.sh&lt;/strong&gt; located in &lt;strong&gt;./devcontainer&lt;/strong&gt; folder has the goal to gather your IP address (the script is inspired by &lt;a href="https://stackoverflow.com/questions/38182286/get-interface-name-into-linux-shell-script-variable." rel="noopener noreferrer"&gt;this one&lt;/a&gt;). The address is set in an environment variable named &lt;strong&gt;REACT_NATIVE_PACKAGER_HOSTNAME&lt;/strong&gt; used by &lt;strong&gt;Expo&lt;/strong&gt; to expose the app. &lt;br&gt;
This variable will'be printed in the file named &lt;strong&gt;.env&lt;/strong&gt; located in the same directory of the script.&lt;/p&gt;

&lt;p&gt;The content of the script:&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
echo "Gathering you ip for dev container"

##############################################################################################
# en (Ethernet) - ib (InfiniBand) - sl (Serial line IP (slip)) - wl (Wireless local area 
network (WLAN)) - ww (Wireless wide area network (WWAN))
#############################################################################################
your_interface_name="eno" 
interface_prefix="en" # Choose the interface network.
iname=$(ip -o link show | sed -rn '/^[0-9]+: en/{s/.: ([^:]*):.*/\1/p}')
ip=`ifconfig $iname  | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | sed 's/inet //g'`

echo "REACT_NATIVE_PACKAGER_HOSTNAME=$ip" &amp;gt; .devcontainer/.env

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

&lt;/div&gt;



&lt;p&gt;The content of the .env file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REACT_NATIVE_PACKAGER_HOSTNAME=192.168.0.72
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The post create command script
&lt;/h2&gt;

&lt;p&gt;The post create command script &lt;strong&gt;postCreateCommand.sh&lt;/strong&gt; located in &lt;strong&gt;./devcontainer&lt;/strong&gt; folder has the goal to set up &lt;strong&gt;Expo&lt;/strong&gt; and &lt;strong&gt;watchman&lt;/strong&gt;  as described in the &lt;a href="https://docs.expo.dev/get-started/installation/" rel="noopener noreferrer"&gt;Expo guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The content of the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo -e "\nStarting post creat command script..."
echo "Dev machine:"
uname -a
echo -e "\nInstalling expo boiler plate..."
npm install --save-dev -y create-expo-app@2.1.1
echo -e "\nInstalling watchman...\n"
sudo apt update
sudo apt install watchman
watchman version

echo -e "\n*******************************"
echo -e "\nDev container ready!".
echo -e "\n*******************************\n"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Create and run the Dev Container
&lt;/h1&gt;

&lt;p&gt;Open the &lt;strong&gt;Command Palette&lt;/strong&gt; (CTRL+SHIFT+P) and select &lt;strong&gt;&lt;em&gt;Rebuild and Reopen in Container&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

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

&lt;h1&gt;
  
  
  Create the app
&lt;/h1&gt;

&lt;p&gt;To create the app, open a terminal inside the dev container and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;animus@mydevcontainer:~$ npx create-expo-app -t blank myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Run the app
&lt;/h1&gt;

&lt;p&gt;To run the app, type the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;animus@mydevcontainer:~$ cd myapp
animus@mydevcontainer:~$ npx expo start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see something like this:&lt;/p&gt;

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

&lt;p&gt;Scan the barcode with the Expo Client App (from your smartphone), and you'll see your app "myapp"!&lt;/p&gt;

&lt;p&gt;Have a fun!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusions
&lt;/h1&gt;

&lt;p&gt;Dev containers are great when you want to prepare a dev environment fully replicable for you and for your team. The little effort that you put at the beginning is well paid off later. Dev containers are useful even in the mobile development using &lt;strong&gt;React Native&lt;/strong&gt; with &lt;strong&gt;Expo&lt;/strong&gt; improving the productivity of the team.&lt;/p&gt;

&lt;p&gt;Suggestions and corrections are welcome.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>containerapps</category>
      <category>react</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to create pull request on GitHub using bash shell and gh command line tool for coding review</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Mon, 10 Jul 2023 21:24:41 +0000</pubDate>
      <link>https://dev.to/animusna/how-to-create-pull-request-on-github-using-bash-shell-and-gh-command-line-tool-for-coding-review-5h6n</link>
      <guid>https://dev.to/animusna/how-to-create-pull-request-on-github-using-bash-shell-and-gh-command-line-tool-for-coding-review-5h6n</guid>
      <description>&lt;p&gt;In this post I show how to create a pull request on &lt;a href="https://github.com/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; to ask a coding review to another coder (e.g. a supervisor, a team leader or just another coder). To do that, I'll use the &lt;strong&gt;bash shell&lt;/strong&gt; and the &lt;strong&gt;GitHub CLI&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you need?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.gnu.org/software/bash/" rel="noopener noreferrer"&gt;Bash shell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/cli/cli" rel="noopener noreferrer"&gt;GitHub CLI&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The script
&lt;/h2&gt;

&lt;p&gt;You can download the script &lt;a href="https://gist.github.com/animusna/35527304f74d500620095c40cfaff6b3" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&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

coder="animusna" # THE CODER NAME WILL RECEIVE THE CODING REVIEW REQUEST
branch="develop" # THE ORIGIN BRANCH ON WHICH YOU'LL MAKE THE PULL REQUEST 

if [ $# -eq 0 ]
  then
    echo "***No arguments supplied"
    exit 1
fi

if [ -z "$1" ]
  then
    echo "***Pull request title not supplied"
    exit 1
fi


if [ -z "$2" ]
  then
    echo "***Pull request message not supplied"
    exit 1
fi

currentBranch=`git rev-parse --abbrev-ref HEAD`

echo -e "\nChecking login status Github cli"

gh auth status

echo -e "\nPushing you branch to origin..."

git push origin $currentBranch

echo -e "\nCreating pull request for branch \"$branch\" asking to \"$coder\" to review...\n"
gh pr create --title "$1" --body "$2" -r $coder -B $branch


echo -e "\n\nbye ;)"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script requires to be configured:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The GitHub account name of the coder will receive the coding review request.&lt;/li&gt;
&lt;li&gt;The branch on which you'll open the pull request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These parameters are hard coded, but you can change the script to receive these values via shell parameters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before to run the script
&lt;/h2&gt;

&lt;p&gt;You'll need to install the GitHub command line tool following &lt;a href="https://github.com/cli/cli#installation" rel="noopener noreferrer"&gt;these instructions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After the setup, you must authenticate typing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;animus@devto:~$gh auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Follow the instructions and complete the authentication process.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  How to run the script
&lt;/h2&gt;

&lt;p&gt;To run the script, you must provide the following parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pull request title&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull request message&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;animus@devto:~$./ps.sh 'smart feature' 'check this out...'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running the script, you'll see something like shown in the image below.&lt;/p&gt;

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

&lt;p&gt;After the execution of the script, the reviewer will receive a notification about the request just created.&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;The script described in this post is very simple, and it shows just one of many potential that the &lt;strong&gt;GitHub CLI&lt;/strong&gt; could offer in a team to collaborate and to automate operations on GitHub repositories.&lt;/p&gt;

</description>
      <category>github</category>
      <category>shell</category>
      <category>git</category>
      <category>codereview</category>
    </item>
    <item>
      <title>Redis: deleting many keys with pattern matching using bash shell + redis-cli</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Tue, 02 May 2023 08:08:51 +0000</pubDate>
      <link>https://dev.to/animusna/redis-deleting-many-keys-with-pattern-matching-using-bash-shell-redis-cli-2bc</link>
      <guid>https://dev.to/animusna/redis-deleting-many-keys-with-pattern-matching-using-bash-shell-redis-cli-2bc</guid>
      <description>&lt;p&gt;Have you ever had the need to delete many keys in a Redis server? If you want to do that, and you don't want to write code (python, c#, java, etc.), you can use the script described in this post.&lt;/p&gt;

&lt;h1&gt;
  
  
  What do you need?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;A bash shell&lt;/li&gt;
&lt;li&gt;Redis installed with authentication enabled. &lt;/li&gt;
&lt;li&gt;Redis-CLI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I assume that you have a basic knowledge of &lt;a href="https://redis.io" rel="noopener noreferrer"&gt;Redis&lt;/a&gt; and &lt;a href="https://redis.io/docs/ui/cli/" rel="noopener noreferrer"&gt;Redis CLI&lt;/a&gt; and &lt;strong&gt;Bash scripting&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  The reason why I made the script
&lt;/h1&gt;

&lt;p&gt;Sometimes you can have the need to remove a set of keys that match with a specific pattern in your Redis server (e.g. "mypattern*", "*mypattern*", "users*", etc.). To reach this goal you can develop a solution in some language (python, c#, java, etc.) or, alternatively, you can use &lt;strong&gt;Redis CLI&lt;/strong&gt;. The script uses the second strategy. &lt;/p&gt;

&lt;h1&gt;
  
  
  How the script works
&lt;/h1&gt;

&lt;p&gt;The script uses &lt;strong&gt;Redis CLI&lt;/strong&gt;, running two commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://redis.io/commands/keys/" rel="noopener noreferrer"&gt;KEYS&lt;/a&gt;, to get all keys match with the input pattern&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://redis.io/commands/del/" rel="noopener noreferrer"&gt;DEL&lt;/a&gt;, to delete the keys (one at once).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The script read before all the keys matching the pattern using the command &lt;strong&gt;Redis CLI KEYS&lt;/strong&gt; and then, it runs the command &lt;strong&gt;Redis CLI DEL&lt;/strong&gt; to remove them. The script, to pipe each key to &lt;strong&gt;Redis CLI DEL&lt;/strong&gt; command, use &lt;a href="https://en.wikipedia.org/wiki/Xargs" rel="noopener noreferrer"&gt;xargs&lt;/a&gt;, so each key can be deleted from Redis.&lt;/p&gt;

&lt;h1&gt;
  
  
  The script
&lt;/h1&gt;

&lt;p&gt;The script has three variables you have to set. The first two are about your installation (&lt;strong&gt;host&lt;/strong&gt; and &lt;strong&gt;port&lt;/strong&gt;) and the third one represents the &lt;strong&gt;pattern&lt;/strong&gt; of keys you need to remove.&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

#######################################################################################################
# Set your parameters
#######################################################################################################
port=6379
host="localhost"
pattern="mypattern*"
#######################################################################################################

echo -e "\nRedis @$host:$port"
echo -e "\nTrying to delete all keys with pattern: $pattern\n"

echo -e "\nEnter Redis Password : "
read -s password

keys_found=`redis-cli -p $port -h $host -a $password --raw --no-auth-warning KEYS $pattern | xargs | wc -w`

if [ "$keys_found" -eq "0" ]; then
    echo -e "\nKeys not found using pattern $pattern\n"  
    exit 1
fi

echo ""
echo "Deleting all keys with pattern $pattern"
redis-cli -p $port -h $host -a $password  --no-auth-warning KEYS $pattern | xargs redis-cli -p $port -h $host -a $password --raw  --no-auth-warning DEL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Run the script
&lt;/h1&gt;

&lt;p&gt;Once you've set the parameters section, run the script!&lt;br&gt;
When the script starts, it'll ask the password to authenticate on your Redis server, provide the password and wait for the conclusion of the execution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
you@yourworkstation$./redis-keys-delete.sh

Redis @localhost:6379

Trying to delete all keys with pattern: mypattern*


Enter Redis Password : 

Deleting all keys with pattern mypattern*
2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This simple script could be useful when you are developing, and you need to remove one or more keys from your Redis server (e.g. deployed with Docker on your workstation). The script could be a starting point to do something different, or it could be improved managing the variables as parameters, and so on. I hope this script could be helpful to someone. Suggestions and corrections are welcome.&lt;/p&gt;

</description>
      <category>redis</category>
      <category>bash</category>
      <category>developer</category>
      <category>nosql</category>
    </item>
    <item>
      <title>Implementing queues with Amazon SQS</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Thu, 10 Nov 2022 09:01:31 +0000</pubDate>
      <link>https://dev.to/animusna/implementing-queues-with-amazon-sqs-56hm</link>
      <guid>https://dev.to/animusna/implementing-queues-with-amazon-sqs-56hm</guid>
      <description>&lt;p&gt;In this post I'll show how to use &lt;strong&gt;&lt;a href="https://aws.amazon.com/it/sqs/" rel="noopener noreferrer"&gt;Amazon Simple Query Service&lt;/a&gt;&lt;/strong&gt; a.k.a. &lt;strong&gt;Amazon SQS&lt;/strong&gt; providing a coding example in &lt;strong&gt;Python&lt;/strong&gt; implementing the "producer consumer problem".&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you need before to start?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS account&lt;/strong&gt;
If you don't have one you can activate it using &lt;a href="https://aws.amazon.com/it/free/?all-free-tier.sort-by=item.additionalFields.SortRank&amp;amp;all-free-tier.sort-order=asc&amp;amp;awsf.Free%20Tier%20Types=*all&amp;amp;awsf.Free%20Tier%20Categories=*all" rel="noopener noreferrer"&gt;free-tier  plan&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/cli/" rel="noopener noreferrer"&gt;AWS CLI&lt;/a&gt; installed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt; basic knowledge level&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python 3&lt;/strong&gt; installed&lt;/li&gt;
&lt;li&gt;Access to a &lt;strong&gt;bash&lt;/strong&gt; shell&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scenario
&lt;/h2&gt;

&lt;p&gt;The goal of this article is to implement a classic consumer/producer problem using a &lt;a href="https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)" rel="noopener noreferrer"&gt;FIFO queue&lt;/a&gt; where a &lt;em&gt;producer&lt;/em&gt; sends one or more messages to a queue and a &lt;em&gt;consumer&lt;/em&gt; receives these messages reading from the same queue. We choose a FIFO queue model to guarantee that the receiving order of the messages is the same of the sending order (pretending that this matters).&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Amazon SQS
&lt;/h2&gt;

&lt;p&gt;From the &lt;a href="https://aws.amazon.com/documentation-overview/sqs/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Amazon Simple Queue Service (SQS) is a managed message queuing service that enables you to decouple and scale microservices, distributed systems, and serverless applications. SQS reduces the complexity of managing and operating message-oriented middleware. SQS is designed so that you can send, store, and receive messages between software components at any volume, without losing messages or requiring other services to be available.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd2u3159clq64q4.cloudfront.net%2Fsqsconsole-20220913172024551%2Fassets%2Fimages%2F5e3f44ce52788a4fb8b8432e4441bf3f-SQS-diagram.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fd2u3159clq64q4.cloudfront.net%2Fsqsconsole-20220913172024551%2Fassets%2Fimages%2F5e3f44ce52788a4fb8b8432e4441bf3f-SQS-diagram.svg" alt="AWS SQS" width="849" height="325"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll use this service to create and use a FIFO queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up the environment
&lt;/h2&gt;

&lt;p&gt;Let's set up the cloud.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure AWS Command Line Interface
&lt;/h3&gt;

&lt;p&gt;To permit to &lt;strong&gt;AWS CLI&lt;/strong&gt; to access to the AWS cloud we need to configure it running the command &lt;strong&gt;aws configure&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;am@animusna:~$aws configure
AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE
AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
Default region name [None]: eu-west-1
Default output format [None]: json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case you need to create the keys follow the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-creds-create" rel="noopener noreferrer"&gt;official guide&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Creation of a FIFO queue
&lt;/h3&gt;

&lt;p&gt;Let's create a FIFO queue running the command &lt;strong&gt;aws sqs create-queue&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;am@animusna:~$aws sqs create-queue --queue-name test.fifo --attributes FifoQueue=true
{
    "QueueUrl": "https://eu-west-1.queue.amazonaws.com/123456789012/test.fifo"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is in JSON format and it represents the URL of the queue that will be used in the demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let's code
&lt;/h2&gt;

&lt;p&gt;The solution is composed by three Python files and one configuration file. &lt;br&gt;
To implement the demo we'll use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/it/sdk-for-python/" rel="noopener noreferrer"&gt;boto3&lt;/a&gt; the official AWS SDK for Python.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pypi.org/project/colorama/" rel="noopener noreferrer"&gt;colorama&lt;/a&gt; module to to prettify the printings in the terminal and used in the demo to make more understandable the outputs of different threads.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Implementing the consumer
&lt;/h3&gt;

&lt;p&gt;In the &lt;strong&gt;consumer.py&lt;/strong&gt; is defined the class &lt;strong&gt;Consumer&lt;/strong&gt; that implements the message reader of the queue. The consumer read one message at a time and after the reading remove it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3
from configparser import ConfigParser
import messageSqs
import warnings

warnings.filterwarnings('ignore', category=FutureWarning, module='botocore.client')

class Consumer:
    def __init__(self, region_name, queue_url,logger):
        self.region_name = region_name
        self.queue_url = queue_url
        self.logger=logger

    def receive_message(self,deleteAfterReceiveing):
        sqs_client = boto3.client("sqs", region_name=self.region_name)
        response = sqs_client.receive_message(
            QueueUrl=self.queue_url,
            MaxNumberOfMessages=1,
            WaitTimeSeconds=15,
        )

        messages=response.get("Messages", [])

        self.logger(f"Number of messages received: {len(messages)}")

        if len(messages)==0:
            return False

        for message in messages:
            m=messageSqs.MessageSqs(jsonStr=message["Body"])
            self.logger(f"\tMessage read from queue: Data:{m.data}\tTime Stamp:{m.ts}\t Id:{m.id}")
            if deleteAfterReceiveing:
                receipt_handle = message['ReceiptHandle']
                dlt_response=sqs_client.delete_message(QueueUrl=self.queue_url,ReceiptHandle=receipt_handle)
                if dlt_response['ResponseMetadata']['HTTPStatusCode']==200:
                    self.logger("\tMessage deleted from queue.")
        return True
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing the producer
&lt;/h3&gt;

&lt;p&gt;In the &lt;strong&gt;producer.py&lt;/strong&gt; it's defined the &lt;strong&gt;Producer&lt;/strong&gt; class that implements the message sender of the queue. The producer create one message at a time to send it to the queue.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import boto3
import uuid
from messageSqs import MessageSqsJSONEncoder
import warnings

warnings.filterwarnings('ignore', category=FutureWarning, module='botocore.client')

class Producer:

    def __init__(self,region_name,queue_url,logger):
        self.region_name = region_name
        self.queue_url= queue_url
        self.logger=logger

    def send_message(self,message):
        sqs_client = boto3.client("sqs", self.region_name)
        self.logger(f"Sending message with id {message.id}...")        
        response = sqs_client.send_message(
            QueueUrl=self.queue_url,
            MessageBody=MessageSqsJSONEncoder().encode(message),
            MessageGroupId="test",
            MessageDeduplicationId=f"DeduplicationId-{uuid.uuid4()}"
        )
        self.logger(f"SQS Response: Status:{response['ResponseMetadata']['HTTPStatusCode']}\tSQS Message Id:{response['MessageId']}")             
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing the scenario
&lt;/h3&gt;

&lt;p&gt;In the module &lt;strong&gt;sqs-demo.py&lt;/strong&gt; we run in different concurrent threads the producer and consumer.The producer send a message each half second for a max of &lt;strong&gt;M&lt;/strong&gt; (where M is &lt;em&gt;PRODUCER_MESSAGES_TO_SENT&lt;/em&gt; defined in configuration file). The consumer try to read a message each half second until there is something to read. The consumer stops after detecting an empty queue for &lt;strong&gt;K&lt;/strong&gt; times (where K is &lt;em&gt;CONSUMER_EXIT_IF_QUEUE_IS_EMPTY_AFTER_ATTEMPTS&lt;/em&gt; defined in the configuration file).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from colorama import Fore
from configparser import ConfigParser
from consumer import Consumer
from datetime import datetime
from messageSqs import MessageSqs
from producer import Producer
import time
import threading
import uuid

config_object = ConfigParser()
config_object.read("config.ini")
aws_conf = config_object["AWS"]
demo_conf = config_object["DEMO"]
message_to_sent = int(demo_conf["PRODUCER_MESSAGES_TO_SENT"])
max_attempts_if_queue_is_empty = int(
    demo_conf["CONSUMER_EXIT_IF_QUEUE_IS_EMPTY_AFTER_ATTEMPTS"])
consumer_start_delay = float(demo_conf["CONSUMER_START_DELAY_IN_SECONDS"])
producer_start_delay = float(demo_conf["PRODUCER_START_DELAY_IN_SECONDS"])


def log(task_name, text, textColor):
    print(textColor + f"{task_name}:{text}" + Fore.WHITE)

def produce_task(task_name="producer"):
    logger=lambda text: log(task_name, text, Fore.YELLOW)
    logger("Running ...")
    time.sleep(producer_start_delay)

    message_index=0
    producer=Producer(aws_conf["REGION"], aws_conf["QUEUE_URL"], logger)
    while (message_index &amp;lt; message_to_sent):
        m=MessageSqs(
            jsonStr = f"{{\"data\":\"mydata{message_index}\",\"ts\":\"{datetime.now().isoformat()}\",\"id\":\"{uuid.uuid4()}\" }}")
        producer.send_message(m)
        message_index += 1
        time.sleep(0.5)
    logger("Terminated!")


def consume_task(task_name = "consumer"):
    logger=lambda text: log(task_name, text, Fore.GREEN)
    receiver = Consumer(aws_conf["REGION"],
                        aws_conf["QUEUE_URL"], logger)
    logger("Running...")
    time.sleep(consumer_start_delay)
    attempts = 0
    while (attempts &amp;lt; max_attempts_if_queue_is_empty):
        if not receiver.receive_message(True):
            attempts += 1
        time.sleep(0.5)

print(Fore.WHITE + '\nStarting demo AWS SQS..\n')

if __name__ == "__main__":
    tasks = []
    tasks.append(threading.Thread(target=produce_task, args=("Producer-SQS",)))
    tasks.append(threading.Thread(target=consume_task, args=("Consumer-SQS",)))

    for t in tasks:
        t.start()

    for t in tasks:
        t.join()

    print(Fore.WHITE + "\n\nAWS SQS Demo terminated!\n\n")

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  The configuration file
&lt;/h3&gt;

&lt;p&gt;In the file &lt;strong&gt;config.ini&lt;/strong&gt; there is the configuration of the demo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[AWS]
REGION = eu-west-1
QUEUE_URL = https://eu-west-1.queue.amazonaws.com/123456789012/test.fifo
[DEMO] 
#Total messages sent by producer
PRODUCER_MESSAGES_TO_SENT = 100
#Delay in seconds before to start the producer
PRODUCER_START_DELAY_IN_SECONDS=0.5
#If the consumer checks the queue is empty it exits after this number of attempts.
CONSUMER_EXIT_IF_QUEUE_IS_EMPTY_AFTER_ATTEMPTS = 10     
#Delay in seconds before to start teh consumer
CONSUMER_START_DELAY_IN_SECONDS=2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Output of the demo
&lt;/h3&gt;

&lt;p&gt;Following some screenshots of the demo in action:&lt;/p&gt;

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

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

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

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

&lt;ul&gt;
&lt;li&gt;Increase the consumers&lt;/li&gt;
&lt;li&gt;Increase the producers&lt;/li&gt;
&lt;li&gt;Change the queue type&lt;/li&gt;
&lt;li&gt;Increase/decrease the visibility timeout&lt;/li&gt;
&lt;li&gt;Read more than one message at a time&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;In this post we've seen how it's easy to implement a consumer/producer problem making use of a FIFO queue hosted in &lt;strong&gt;AWS SQS&lt;/strong&gt;. The use of the official SDK &lt;strong&gt;Boto3&lt;/strong&gt; it's very intuitive as much as the &lt;strong&gt;AWS cli&lt;/strong&gt; that in one only command allowed us to create a new queue.&lt;/p&gt;

&lt;p&gt;You can find the sources on &lt;a href="https://github.com/animusna/aws-sqs-demo" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>cloud</category>
      <category>python</category>
      <category>programming</category>
    </item>
    <item>
      <title>Numeric Overflow management in C#, Java, JavaScript and Python</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Tue, 25 Oct 2022 10:34:17 +0000</pubDate>
      <link>https://dev.to/animusna/numeric-overflow-management-in-c-java-javascript-and-python-30fi</link>
      <guid>https://dev.to/animusna/numeric-overflow-management-in-c-java-javascript-and-python-30fi</guid>
      <description>&lt;p&gt;Do you now what happens when you increment by one the maximum value of a number? &lt;/p&gt;

&lt;p&gt;The most common and logic answer: I get a &lt;strong&gt;Numeric Overflow Exception&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But the real answer is not always or probably never!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you don't know how your compiler manage this kind of situation you could design bad algorithms with wrong solutions.&lt;/p&gt;

&lt;p&gt;Let's prove that!&lt;/p&gt;

&lt;h2&gt;
  
  
  C#
&lt;/h2&gt;

&lt;p&gt;In C# when you increment a max value you don't get a numeric overflow exception (this is a default behavior). Take a look to the following snippet, where the max integer value (2147483647) is incremented by one.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;int count=int.MaxValue;
Console.WriteLine($"count is {++count}");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in this case the output will be &lt;strong&gt;-2147483648&lt;/strong&gt; that is clearly an overflow because we get a negative number after an increment of positive number.This happens because the increment rises the most significant bit of the number, the sign bit (+/-).&lt;/p&gt;

&lt;p&gt;To trigger an overflow/underflow exception we need to put the operation in a &lt;strong&gt;checked&lt;/strong&gt; block 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;int count = int.MaxValue;
checked
{
    Console.WriteLine($"count is {++count}");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we go, the exception is served! &lt;br&gt;
&lt;code&gt;'System.OverflowException' in overflow-dotnet.dll: 'Arithmetic operation resulted in an overflow.'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;C# compiler&lt;/strong&gt; you can enable the option &lt;a href="https://dev.toCheckForOverflowUnderflow"&gt;CheckForOverflowUnderflow&lt;/a&gt; where &lt;em&gt;the default context is a checked context and overflow checking is enabled&lt;/em&gt; (and complementary you can use the keyword &lt;strong&gt;unchecked&lt;/strong&gt; to uncheck the context).&lt;/p&gt;
&lt;h2&gt;
  
  
  Java
&lt;/h2&gt;

&lt;p&gt;In Java the behavior is very similar to what happens in C#, take a look to the following snippet!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Integer count=Integer.MAX_VALUE; // 2147483647
System.out.println(String.format("count is %d",++count));
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in this case the output will be &lt;strong&gt;-2147483648&lt;/strong&gt; that is clearly an overflow like in previous example.&lt;/p&gt;

&lt;p&gt;From Java 8 &lt;strong&gt;&lt;a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html" rel="noopener noreferrer"&gt;Math&lt;/a&gt;&lt;/strong&gt; class provides a set of operations (decrementExact, addExact,multiplyExact, etc. ) for  "checked" arithmetic operations against numeric overflow/underflow.&lt;/p&gt;

&lt;p&gt;To trigger an overflow exception we need to use &lt;strong&gt;&lt;a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#incrementExact-int-" rel="noopener noreferrer"&gt;Math.incrementExact&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;that returns the argument incremented by one, throwing an exception if the result overflows an int&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Integer count=Integer.MAX_VALUE; // 2147483647
Math.incrementExact(count);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;here we go, the exception is served:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Exception in thread "main" java.lang.ArithmeticException: integer overflow at java.base/java.lang.Math.incrementExact(Math.java:964)&lt;br&gt;
    at Main.main(Main.java:12)&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  JavaScript
&lt;/h2&gt;

&lt;p&gt;In JavaScript too we don't have an overflow exception if we increment a maximum value of a number and, at moment of writing, there is no way to detect a numeric overflow exception unless you write a custom function to reach this goal.&lt;/p&gt;

&lt;p&gt;Let's prove that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let counter=Number.MAX_VALUE;
console.log(++counter);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous snippet we are incrementing by one the maximum value of &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number" rel="noopener noreferrer"&gt;Number&lt;/a&gt; represented by the constant &lt;strong&gt;Number.MAX_VALUE&lt;/strong&gt;. The output of this snippet is &lt;strong&gt;1.7976931348623157e+308&lt;/strong&gt; the original value of the variable &lt;em&gt;counter&lt;/em&gt; (so the increment has non effect).&lt;/p&gt;

&lt;p&gt;But how detect an numeric overflow/underflow JavaScript?&lt;/p&gt;

&lt;p&gt;In this &lt;a href="https://www.algotech.solutions/blog/javascript/handle-number-overflow-javascript/" rel="noopener noreferrer"&gt;article from algotech.solutions&lt;/a&gt; there are good arithmetic considerations that bring to implement custom functions to detect numeric overflow/underflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python
&lt;/h2&gt;

&lt;p&gt;In Python 3 integers haven't fixed size (&lt;a href="https://www.techbeamers.com/why-python-integer-size-bigger-than-c/" rel="noopener noreferrer"&gt;this article explain how they are structured&lt;/a&gt;) and the only limit is the available memory. For this reason the following code could never stop until the memory is available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from time import sleep

count=int(0)
step = int(10**10000)
while(True):
    count+=step
    sleep(0.2)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want have more control about the dimension of the integers we can use &lt;strong&gt;&lt;a href="https://numpy.org" rel="noopener noreferrer"&gt;NumPy&lt;/a&gt;&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;import sys
import numpy as np

count=np.int64(sys.maxsize)
count+=1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we go the exception is served:&lt;br&gt;
&lt;code&gt;RuntimeWarning: overflow encountered in long_scalars&lt;br&gt;
  count+=1&lt;br&gt;
-9223372036854775808&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;Detecting a &lt;em&gt;numeric overflow/underflow&lt;/em&gt; is &lt;strong&gt;expensive&lt;/strong&gt; and for this reason many programming languages have as default behavior to ignore it and leave to the programmer to decide if check or uncheck an arithmetic operation. &lt;/p&gt;

&lt;p&gt;What's really matters is the knowledge of the problem and how the implementation of the programming language approaches to this kind of situations. Ignoring or overlooking the problem could lead to an &lt;strong&gt;unexpected results&lt;/strong&gt; and &lt;strong&gt;security flaws&lt;/strong&gt; (in some scenarios). &lt;/p&gt;

&lt;p&gt;This article has been written because many years ago I wrote an algorithm for a challenge on &lt;strong&gt;&lt;a href="https://www.hackerrank.com/" rel="noopener noreferrer"&gt;Hackerrank&lt;/a&gt;&lt;/strong&gt; and a silent overflow made fail it (long story short I wasted a lot of time to figure out the nature of the problem).&lt;/p&gt;

&lt;p&gt;Suggestions and corrections are welcome.&lt;/p&gt;

&lt;p&gt;See you&lt;/p&gt;

&lt;p&gt;AM&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>javascript</category>
      <category>java</category>
      <category>python</category>
    </item>
    <item>
      <title>Docker Secrets in Swarm: Redis use case</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Wed, 19 Oct 2022 11:02:06 +0000</pubDate>
      <link>https://dev.to/animusna/docker-secrets-in-swarm-39ee</link>
      <guid>https://dev.to/animusna/docker-secrets-in-swarm-39ee</guid>
      <description>&lt;p&gt;In this post I want show how to use &lt;strong&gt;&lt;a href="https://docs.docker.com/engine/swarm/secrets/" rel="noopener noreferrer"&gt;Docker Secrets&lt;/a&gt;&lt;/strong&gt; providing a real scenario example using &lt;strong&gt;Redis&lt;/strong&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What do you need before reading this article?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of Docker technology&lt;/li&gt;
&lt;li&gt;Basic knowledge of Docker Swarm orchestrator&lt;/li&gt;
&lt;li&gt;Basic knowledge of Redis&lt;/li&gt;
&lt;li&gt;Docker installed &lt;/li&gt;
&lt;li&gt;Access to a Bash shell&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What are Docker secrets?
&lt;/h1&gt;

&lt;p&gt;I just quote the definition provided from documentation:&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;In terms of Docker Swarm services, a secret is a blob of data, such as a password, SSH private key, SSL certificate, or another piece of data that should not be transmitted over a network or stored unencrypted in a Dockerfile or in your application’s source code. ...&lt;/em&gt;"&lt;/p&gt;

&lt;h1&gt;
  
  
  How to create them?
&lt;/h1&gt;

&lt;p&gt;To create a secret you have to run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animusna:~$echo "myPlainSecret" | docker secret create mysecret
acvs814nso28yn105wqc32o8e
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output of this command is the id (acvs814nso28yn105wqc32o8e) of the secret.&lt;/p&gt;

&lt;p&gt;To check if your secret has been created run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animusna:~$docker secret ls
ID                          NAME       DRIVER    CREATED         UPDATED
acvs814nso28yn105wqc32o8e   mysecret             5 seconds ago   5 seconds ago
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  How to use them?
&lt;/h1&gt;

&lt;p&gt;To use a secret you have to map it during the creation of a service (in this case &lt;strong&gt;redis&lt;/strong&gt; like in the &lt;a href="https://docs.docker.com/engine/swarm/secrets/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animusna:~$docker service create --name redis --secret mysecret redis:alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you map secret in a service, Docker creates a file named like the &lt;em&gt;secret name&lt;/em&gt; (in this case &lt;strong&gt;&lt;em&gt;mysecret&lt;/em&gt;&lt;/strong&gt;) in the folder &lt;strong&gt;&lt;em&gt;/run/secrets&lt;/em&gt;&lt;/strong&gt; and to prove that we can run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animusna:~$docker container exec $(docker ps --filter name=redis -q) cat /run/secrets/mysecret
myPlainSecret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where the output will be the plain text of the secret that we have created (&lt;em&gt;myPlainSecret&lt;/em&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Real scenario example: Redis authentication with Docker secret
&lt;/h2&gt;

&lt;p&gt;In case we want protect our &lt;strong&gt;Redis&lt;/strong&gt; server we could use the secret created previously as password to connect to our server.&lt;/p&gt;

&lt;p&gt;Let's prepare our docker compose file :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: "3.1"
secrets:
  mysecret:
    external: true  #external=true means we've created the secret before. 

services:
  redis:
    image: redis 
    secrets:
      - mysecret   #We are declaring we are using this secret in this service. 
    command: bash -c "/startup/up-redis.sh" #The command we use to start our Redis server (we execute a shell script).
    ports:
      - "6379:6379"
    volumes:
      - "/home/am/up-redis.sh:/startup/up-redis.sh" # Mapping in the container our script.
    deploy:
      replicas: 1
      restart_policy:
        condition: on-failure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's prepare the start up script for our server &lt;strong&gt;up-redis.sh&lt;/strong&gt; in a specific path (in my case &lt;em&gt;/home/am/&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/sh
#Script to startup Redis Server.

#Reading secret in a temporary variable.
REDIS_PASSWORD=`cat /run/secrets/mysecret`

#Start Redis server
redis-server --appendonly yes --requirepass "$REDIS_PASSWORD"  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this script we set the password for our server using the option &lt;strong&gt;--requirepass&lt;/strong&gt; recovering the secret from &lt;strong&gt;/run/secrets/mysecret&lt;/strong&gt; and putting it inside the variable &lt;strong&gt;REDIS_PASSWORD&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Now that is everything ready we can start service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animusna:~$docker stack deploy --compose-file=docker-compose.yaml myapp_stack
Creating network myapp_stack_default
Creating service myapp_stack_redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To check if we've set the secret to access to our Redis service let's run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;am@animusna:~$echo -e "AUTH myPlainSecret\nPING" | redis-cli
OK
PONG
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where we run in the &lt;strong&gt;redis-cli&lt;/strong&gt; the command &lt;strong&gt;AUTH&lt;/strong&gt; for authenticate with our plain secret &lt;strong&gt;&lt;em&gt;myPlainSecret&lt;/em&gt;&lt;/strong&gt; and then the command &lt;strong&gt;PING&lt;/strong&gt; to check if we are authenticated (in our case yes because we get a &lt;em&gt;PONG&lt;/em&gt;).&lt;/p&gt;

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

&lt;p&gt;In this article I've shown a possible and easy use of Docker secrets to protect sensitive data like it could be a  connection password. The use of secrets are very useful in deployment scenario as much as in development scenario where developers should use their own secrets to configure their development environment. According my experience Docker secrets are useful and easy to manage and it's worth to use them if you choose &lt;strong&gt;Docker Swarm&lt;/strong&gt; as orchestrator for your (micro) services.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>redis</category>
      <category>bash</category>
    </item>
    <item>
      <title>Dockysh: a shell written in Python over Docker shell</title>
      <dc:creator>Aniello Musella</dc:creator>
      <pubDate>Sat, 02 Oct 2021 08:21:55 +0000</pubDate>
      <link>https://dev.to/animusna/dockysh-a-shell-written-in-python-over-docker-shell-44mc</link>
      <guid>https://dev.to/animusna/dockysh-a-shell-written-in-python-over-docker-shell-44mc</guid>
      <description>&lt;p&gt;In this post I share a new small project to realize a simple and friendly shell that enrich the classical &lt;strong&gt;docker shell&lt;/strong&gt; reducing the necessary verbosity that characterizes this shell. It can happening that during the development activities you  need to interact with &lt;em&gt;containers&lt;/em&gt;, &lt;em&gt;images&lt;/em&gt;, &lt;em&gt;services&lt;/em&gt; performing actions like &lt;em&gt;start&lt;/em&gt;,&lt;em&gt;remove&lt;/em&gt;,&lt;em&gt;stop&lt;/em&gt; and so on. Using &lt;strong&gt;Docker shell&lt;/strong&gt; makes you to repeat some keywords that you would gladly avoid to save time.&lt;/p&gt;

&lt;p&gt;Following I publish the &lt;a href="https://github.com/animusna/dockysh#readme" rel="noopener noreferrer"&gt;readme&lt;/a&gt; of the project.&lt;/p&gt;

&lt;h1&gt;
  
  
  What's Dockysh
&lt;/h1&gt;

&lt;p&gt;A "wrapper" shell written in Python over &lt;strong&gt;Docker Shell&lt;/strong&gt;. &lt;br&gt;
&lt;strong&gt;Dockysh&lt;/strong&gt; try to speedup the typing of commands for Docker shell reducing the verbosity of command and in some cases providing a little of interactivity.&lt;/p&gt;
&lt;h1&gt;
  
  
  Disclaimer
&lt;/h1&gt;

&lt;p&gt;Dockysh does not replace Docker Shell but it's based on it. Dockysh use the &lt;strong&gt;Python library&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://docs.python.org/3/library/cmd.html" rel="noopener noreferrer"&gt;cmd&lt;/a&gt;&lt;/strong&gt; and little of &lt;strong&gt;Bash&lt;/strong&gt; scripting to make easier and more user friendly some commands.&lt;/p&gt;
&lt;h1&gt;
  
  
  Why this shell
&lt;/h1&gt;

&lt;p&gt;For people that make an intense and interactive use of Docker shell &lt;strong&gt;Dockysh&lt;/strong&gt; permit you to avoid to repeat some keywords like &lt;em&gt;docker container&lt;/em&gt;, &lt;em&gt;docker images&lt;/em&gt; and so on. For instance instead of type &lt;em&gt;docker container ls&lt;/em&gt; you can type&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;you@Dokysh$ lsc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and if you want filter the results you can type the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;you@Dokysh$ lsc your_string_filter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  What you need to run this shell
&lt;/h1&gt;

&lt;p&gt;To run this shell you need:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Bash shell&lt;/li&gt;
&lt;li&gt;Docker installed&lt;/li&gt;
&lt;li&gt;Python installed&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For who want use this shell in &lt;em&gt;Windows&lt;/em&gt; you can activate the &lt;em&gt;&lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10" rel="noopener noreferrer"&gt;Windows Subsystem for Linux&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How this shell works
&lt;/h1&gt;

&lt;p&gt;The shell is provided with a set of commands. Each command is just an alias to a specific &lt;strong&gt;Docker Shell&lt;/strong&gt; command. Each alias command is translated and sent to &lt;strong&gt;Docker Shell&lt;/strong&gt;. In case of command not mapped the shell try to run the command in &lt;strong&gt;Docker shell&lt;/strong&gt;, so if you type the wrong command &lt;em&gt;command_not_mapped with_args&lt;/em&gt; the shell try to run &lt;strong&gt;docker command_not_mapped with_args&lt;/strong&gt;. As logical consequence you can run  each &lt;strong&gt;Docker shell command&lt;/strong&gt; without the prefix &lt;em&gt;docker&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to run the shell
&lt;/h1&gt;

&lt;p&gt;Just run the following command: &lt;code&gt;python dockysh.py&lt;/code&gt; and then type &lt;em&gt;?&lt;/em&gt; or &lt;em&gt;help&lt;/em&gt; for help:&lt;code&gt;you@Dokysh$ help&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Examples
&lt;/h1&gt;

&lt;p&gt;Following some examples of &lt;strong&gt;Dockysh&lt;/strong&gt; commands.&lt;/p&gt;

&lt;p&gt;Finding an image: &lt;code&gt;you@Dokysh$ lsi alpine&lt;/code&gt; where &lt;em&gt;alpine&lt;/em&gt; is a filter and return all Alpine images like shown following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;you@Dokysh$ lsi alpine
REPOSITORY                                  TAG                              IMAGE ID       CREATED         SIZE
alpine                                      latest                           d4ff818577bc   6 weeks ago     6.4MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove one or more images: &lt;code&gt;you@Dokysh$ rmi alpine&lt;/code&gt; where &lt;em&gt;alpine&lt;/em&gt; is a filter. &lt;br&gt;
In this case each image corresponding the filter provided will be removed after confirmation by the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;you@Dokysh$ rmi alpine

Found 1 images in base your filter 'alpine'. Please confirm the deletion of the images found.

Do you want eliminate the image with id "d4ff818577bc" with tag "latest" of size "6.4MB" from repository "alpine"" ?
([Y]=&amp;gt; yes/ [N]=&amp;gt;no / [E]=&amp;gt; exit from this operation):Y

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

&lt;/div&gt;



&lt;p&gt;Finding container stopped: &lt;code&gt;you@Dokysh$ lsc down&lt;/code&gt; where &lt;em&gt;down&lt;/em&gt; is a filter on container status&lt;/p&gt;

&lt;p&gt;Finding container running: &lt;code&gt;you@Dokysh$ lsc up&lt;/code&gt; where &lt;em&gt;up&lt;/em&gt; is a filter on container status&lt;/p&gt;

&lt;p&gt;Finding container running: &lt;code&gt;you@Dokysh$ lsc b33526d46134&lt;/code&gt; where &lt;em&gt;b33526d46134&lt;/em&gt; is a filter on image of the container.&lt;/p&gt;

&lt;p&gt;Finding containers by image id: &lt;code&gt;you@Dokysh$ lsc b33526d46134&lt;/code&gt; where &lt;em&gt;b33526d46134&lt;/em&gt; is a filter on image of the container.&lt;/p&gt;

&lt;p&gt;Removing a container: &lt;code&gt;you@Dokysh$ rmc 192294a228b7&lt;/code&gt; where &lt;em&gt;192294a228b7&lt;/em&gt; is a filter representing the id of the container.&lt;/p&gt;

&lt;p&gt;In this case each contianer corresponding the filter provided (one because we've used the id of container) will be removed after confirmation by the user:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found 1 containers in base your filter '192294a228b7'. Please confirm the deletion of the containers found.

Do you want eliminate the container with id "192294a228b7" based on image with ID "b33526d46134" ?
([Y]=&amp;gt; yes/ [N]=&amp;gt;no / [E]=&amp;gt; exit from this operation): Y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Next steps
&lt;/h1&gt;

&lt;p&gt;Improving the shell.&lt;/p&gt;

&lt;p&gt;See you&lt;/p&gt;

&lt;p&gt;AM&lt;/p&gt;

</description>
      <category>python</category>
      <category>docker</category>
      <category>bash</category>
      <category>container</category>
    </item>
  </channel>
</rss>
