<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Stelios Sotiriadis</title>
    <description>The latest articles on Forem by Stelios Sotiriadis (@steliosot).</description>
    <link>https://forem.com/steliosot</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%2F2315143%2F5d31f0af-a0e3-4173-8f6d-4267874d8ce3.png</url>
      <title>Forem: Stelios Sotiriadis</title>
      <link>https://forem.com/steliosot</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/steliosot"/>
    <language>en</language>
    <item>
      <title>PR &amp; GitHub Actions updates, now synced with Linear.</title>
      <dc:creator>Stelios Sotiriadis</dc:creator>
      <pubDate>Wed, 01 Oct 2025 06:56:39 +0000</pubDate>
      <link>https://forem.com/steliosot/pr-github-actions-updates-now-synced-with-linear-55m6</link>
      <guid>https://forem.com/steliosot/pr-github-actions-updates-now-synced-with-linear-55m6</guid>
      <description>&lt;h4&gt;
  
  
  Visibility is the key!
&lt;/h4&gt;

&lt;p&gt;Over the past few months, I’ve been working on a project that solves a small but painful problem for my team: &lt;strong&gt;keeping track of DevOps events across GitHub and Linear&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%2Fy3ttsu46v0jcpm3m2qhx.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%2Fy3ttsu46v0jcpm3m2qhx.png" alt="GitHub-Linear integration" width="800" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We often missed important updates because they lived in GitHub while our planning and tracking lived in Linear. That disconnect caused delays, confusion, and extra manual work for all our PMs, developers and SREs.  &lt;/p&gt;

&lt;p&gt;When events started showing up in Linear instantly, everything became easier. It helped us:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Catch problems right away.
&lt;/li&gt;
&lt;li&gt;Work together as one team — PMs, Devs, and SREs all share the same view.
&lt;/li&gt;
&lt;li&gt;And since we’re chasing SOC-2 compliance, every event and violation was automatically documented for audits.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  What we built
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;We implemented a Warestack feature that integrates GitHub and Linear. The idea was to be flexible: one team might only need PR updates, another might want GitHub Actions, and others might need to know about protection rule violations. We focused on events like &lt;code&gt;GitHub issues&lt;/code&gt;, &lt;code&gt;PRs&lt;/code&gt;, &lt;code&gt;deployment reviews&lt;/code&gt;, and &lt;code&gt;workflow runs&lt;/code&gt;.  &lt;/p&gt;

&lt;p&gt;Our decision was simple — deliver these updates as &lt;strong&gt;comments in the related Linear tickets&lt;/strong&gt;. And it worked.  &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  A simple example
&lt;/h4&gt;

&lt;p&gt;Say our team opens a pull request without the required reviewers. Normally, this would slip through unnoticed until much later — probably after it caused delays or, worse, a broken release.  &lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Warestack&lt;/strong&gt;, the violation is caught right away. The related Linear issue is automatically updated, and both Developers and PMs get instant visibility — no extra work required.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Easy setup
&lt;/h4&gt;

&lt;p&gt;We wanted this to be frictionless. Setup takes just a couple of minutes, 1' to connect, 1' to configure and done.&lt;/p&gt;

&lt;h4&gt;
  
  
  Getting started
&lt;/h4&gt;

&lt;p&gt;This tutorial walks you through how to:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect Linear.
&lt;/li&gt;
&lt;li&gt;Configure triggers.
&lt;/li&gt;
&lt;li&gt;Automatically receive DevOps updates (PRs, workflow runs, rule violations) as comments inside your Linear tickets.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;👉 You can find the tutorial &lt;a href="https://www.youtube.com/playlist?list=PLlw8SkBz9moUFQpRsKvIut-7U7U3AM14Y&amp;amp;feature=shared" rel="noopener noreferrer"&gt;here&lt;/a&gt;.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Connect Linear
&lt;/h4&gt;

&lt;p&gt;You only need to do this once.  &lt;/p&gt;

&lt;p&gt;From the Warestack dashboard, go to &lt;strong&gt;Integrations&lt;/strong&gt; to view available software connections. Click &lt;strong&gt;Connect&lt;/strong&gt; next to Linear to start the installation.  &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%2F4ysyr001m1f15s603ia2.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%2F4ysyr001m1f15s603ia2.png" alt="Connect Warestack - Linear" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Authorize Warestack in Linear by granting the requested permissions and clicking &lt;strong&gt;Authorize&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%2Fx2ozcbntfdrdpiv833b4.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%2Fx2ozcbntfdrdpiv833b4.png" alt="Authorize Warestack in Linear" width="800" height="703"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once connected, you’ll see a success message confirming Linear is active.  &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%2Ft2y020p98nt856hsfkg0.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%2Ft2y020p98nt856hsfkg0.png" alt="Success message" width="800" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Activate Post Actions
&lt;/h4&gt;

&lt;p&gt;Open &lt;strong&gt;Post actions&lt;/strong&gt; from the left menu to configure what happens inside Linear after events are executed.  &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%2Fe6yrr3fcmhu9nlj23m25.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%2Fe6yrr3fcmhu9nlj23m25.png" alt="Start configuration" width="800" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Linear Integration&lt;/strong&gt; to create your first post action and start receiving automatic comments in Linear for Warestack events. You can select your preferred combinations of events to send. &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%2F9tmpsc6231ypc4jz4buc.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%2F9tmpsc6231ypc4jz4buc.png" alt="Create post action" width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select a &lt;strong&gt;team&lt;/strong&gt;, &lt;strong&gt;event type&lt;/strong&gt;, &lt;strong&gt;trigger conditions&lt;/strong&gt;, and the &lt;strong&gt;Linear team&lt;/strong&gt; that should receive the comments, then save the action. You can also configure additional rule violation triggers (e.g., “PRs must have at least 2 reviewers”). Configured actions will now appear in the Linear card.  &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%2Fbuc43ff18js46oy4y7vp.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%2Fbuc43ff18js46oy4y7vp.png" alt="Add more as needed" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well done! 🎉 Your first trigger is live. &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%2Fgwy3scdrnvl8oelzqm3k.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%2Fgwy3scdrnvl8oelzqm3k.png" alt="Confirm active configuration" width="800" height="617"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Work as Usual
&lt;/h4&gt;

&lt;p&gt;Continue working as you normally would. Warestack runs in the background, checking events and automatically commenting when violations occur.  &lt;/p&gt;

&lt;p&gt;Check your Linear where updated it your ticket.  &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%2Fipbiy6ke5kwe3xr7y68e.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%2Fipbiy6ke5kwe3xr7y68e.png" alt="Check Linear workspace" width="800" height="576"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down to view the comments Warestack added. Everything happening in your operational workflows is now documented directly inside your tickets.  &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%2Foifkpvw00ys0lau5a2nk.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%2Foifkpvw00ys0lau5a2nk.png" alt="Inspect Warestack comments" width="800" height="704"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Having trouble?
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/stelios-sotiriadis/" rel="noopener noreferrer"&gt;Connect with me&lt;/a&gt; and we’ll figure it out together.&lt;/p&gt;

&lt;h4&gt;
  
  
  Warestack Does Not Stop Here!
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiple actions&lt;/strong&gt;: You can configure multiple Linear post actions per team, repo, or rule.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free forever&lt;/strong&gt;: Linear integration is included in the free plan, so you can try it out with your favorite repository at no cost.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-channel visibility&lt;/strong&gt;: Combine with Slack notifications (or Jira) to keep your team in sync everywhere.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;End-to-end associations&lt;/strong&gt;: Warestack links pull requests → workflow runs → tickets → rule violations, giving you a complete DevOps activity graph inside your project management tool.
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>github</category>
      <category>linear</category>
      <category>githubactions</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How do you catch pretty much every bug before it hits prod?</title>
      <dc:creator>Stelios Sotiriadis</dc:creator>
      <pubDate>Thu, 25 Sep 2025 16:33:43 +0000</pubDate>
      <link>https://forem.com/steliosot/custom-protection-rules-4gd</link>
      <guid>https://forem.com/steliosot/custom-protection-rules-4gd</guid>
      <description>&lt;h2&gt;
  
  
  ⚡ Release Code Like a Pro ⚡
&lt;/h2&gt;

&lt;p&gt;If you lead a dev team, or want to code like one, this article is for you. Writing code with AI is easy; delivering it safely and reliably is where great engineers stand out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.warestack.com" rel="noopener noreferrer"&gt;YOU NEED TO TRY WARESTACK TODAY!&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I shot a set of videos that show you how to use agentic protection rules, all in less than 10 minutes!&lt;/p&gt;
&lt;h3&gt;
  
  
  What agentic protection means?
&lt;/h3&gt;

&lt;p&gt;Just describe your rule in plain English, turn it on, and carry on working as usual. Warestack keeps an eye on your PRs, workflows, and other events, flagging them when something doesn’t meet the rules.&lt;/p&gt;
&lt;h3&gt;
  
  
  What rules can I create?
&lt;/h3&gt;

&lt;p&gt;Type any rule you can imagine. Here’s what other users built to keep GitHub PR changes in check.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if a .sql file changes, require a matching migration script.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Flag PRs with heavy AI-generated code.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;WATCH THE PLAYLIST!&lt;br&gt;
↓↓↓↓↓↓↓↓↓↓↓↓↓↓&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/playlist?list=PLlw8SkBz9moUFQpRsKvIut-7U7U3AM14Y" rel="noopener noreferrer"&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%2F0kkjoxzqbkq5e7x8fr4m.png" alt="Warestack" width="800" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why this matters?
&lt;/h3&gt;

&lt;p&gt;You know best what your team does today and where the biggest risks are. Now you know how to create the rules that matters to YOUR TEAM!&lt;/p&gt;

&lt;h3&gt;
  
  
  Wanna try it?
&lt;/h3&gt;

&lt;p&gt;Visit: &lt;a href="https://www.warestack.com" rel="noopener noreferrer"&gt;https://www.warestack.com&lt;/a&gt; and sign up for a month's free trial.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do you like it? Drop me an email I will give you 6 months free access: &lt;a href="mailto:stelios.sotiriadis@warestack.com"&gt;stelios.sotiriadis@warestack.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>warestack</category>
      <category>devops</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Agentic DevOps: The Future of Adaptive Governance</title>
      <dc:creator>Stelios Sotiriadis</dc:creator>
      <pubDate>Wed, 20 Aug 2025 09:23:33 +0000</pubDate>
      <link>https://forem.com/steliosot/agentic-devops-the-future-of-adaptive-governance-3m56</link>
      <guid>https://forem.com/steliosot/agentic-devops-the-future-of-adaptive-governance-3m56</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.producthunt.com/products/warestack?launch=warestack-3" rel="noopener noreferrer"&gt;WE JUST RELEASED IN PRODUCT HUNT!&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Right now, there are only two common approaches to branch protection.&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%2Fxq9wyaom6eypktcyiivt.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%2Fxq9wyaom6eypktcyiivt.png" alt="Current branch protection ways" width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For years, DevOps protection relied on these rigid, static rules. YAML configs, hardcoded scripts, forms, and CI workflows enforced guardrails, but they couldn’t keep up with today’s fast, multi-repo SaaS environments. But what if your team deploys hundreds of times per week? These outdated protections leave critical gaps, blind to urgency, team structure, or operational context. &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%2F9ezcfcniqo701i1cyn4x.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%2F9ezcfcniqo701i1cyn4x.png" alt=" " width="800" height="974"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The result? Workarounds, skipped checks, and rules drifting out of sync.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At Warestack, we believe DevOps needs to evolve. That’s where Agentic DevOps comes in. Instead of static rules, agentic governance brings adaptive, AI-driven protection that reacts in real time to developer roles, urgency, and live activity. Think of it as a process checker for your pipeline — watching every event, flagging unsafe operations, and blocking risky merges before they hit production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We put this approach to the test.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;In an experiment with 100 pull requests across major open-source repos like &lt;code&gt;VSCode&lt;/code&gt;, &lt;code&gt;React&lt;/code&gt;, &lt;code&gt;Terraform&lt;/code&gt;, &lt;code&gt;PyTorch&lt;/code&gt;, and &lt;code&gt;Kubernetes&lt;/code&gt;, agentic governance uncovered up to 8× more violations than traditional methods, with coverage rates as high as 95%. It caught issues static rules missed — vague PR descriptions, review gaps, or unapproved changes to sensitive code paths — all while adapting across teams and repo structures without hardcoding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is a Agentic DevOps?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A way to define the boundaries of how your team should operate, specifying what’s allowed, what’s enforced, and where flexibility is permitted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The impact is clear.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With &lt;a href="https://www.warestack.com/" rel="noopener noreferrer"&gt;Warestack&lt;/a&gt;, you can write protection rules in plain English, monitor every operation in a single dashboard, and generate audit-ready reports instantly. What once took hours of manual configuration now takes seconds. And with one-click integrations for tools like Slack and Linear, enforcement extends seamlessly into your daily workflows.&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%2F2l2rmew5u1h6vzlfmyxl.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%2F2l2rmew5u1h6vzlfmyxl.png" alt="Meet Warestack" width="800" height="1002"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The future of DevOps isn’t static; it’s adaptive. Agentic DevOps ensures your pipelines are accessible, context-aware, and secure — protecting critical releases without slowing teams down. We’ve shared our full findings, lessons learned, and open-source contribution in the newly released white paper.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://eu1.hubs.ly/H0mrwZl0" rel="noopener noreferrer"&gt;👉 Read the full article&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>githubactions</category>
      <category>devops</category>
      <category>observability</category>
    </item>
    <item>
      <title>Enforce DevOps best practices and eliminate production errors!</title>
      <dc:creator>Stelios Sotiriadis</dc:creator>
      <pubDate>Thu, 02 Jan 2025 20:21:03 +0000</pubDate>
      <link>https://forem.com/steliosot/enforce-devops-best-practices-and-eliminate-production-errors-43d5</link>
      <guid>https://forem.com/steliosot/enforce-devops-best-practices-and-eliminate-production-errors-43d5</guid>
      <description>&lt;p&gt;We’re developers, and we love best practices—but let’s be honest, we often bypass them.  &lt;/p&gt;

&lt;p&gt;And you know what? That’s okay! You are not alone! &lt;/p&gt;

&lt;p&gt;This popular GitHub post resonates!&lt;/p&gt;

&lt;p&gt;People will forget all your contributions and hard work but not the time you were forced to push into the main branch!&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%2Fof14bdruvxyqidlqjuzb.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%2Fof14bdruvxyqidlqjuzb.png" alt="Image description" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Because sometimes speed, urgency, or unforeseen challenges force us to take shortcuts. The real problem isn’t occasional bypassing—it’s when these bypasses go unnoticed, untracked, and unaddressed.  &lt;/p&gt;

&lt;p&gt;Best practices aren’t about perfection; they’re about &lt;strong&gt;consistency, visibility, and accountability&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;That's why we rely on an ever-growing stack of tools to automate our processes. We trust these tools! For example:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Jenkins&lt;/strong&gt; for CI/CD
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt; for code management
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jira&lt;/strong&gt; for task tracking
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here’s the issue:  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;These tools operate in isolation—they don’t share context.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In a recent interview, a tech leader shared:&lt;br&gt;&lt;br&gt;
&lt;em&gt;"A failed test in GitHub doesn’t stop a Jira ticket from being marked as 'Done'."&lt;/em&gt;  &lt;/p&gt;

&lt;p&gt;That’s a bad practice—and it leads to teams firefighting 500 errors in production, blindfolded and in the dark.  &lt;/p&gt;

&lt;p&gt;Who knows what caused the error?  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Was it a skipped test?
&lt;/li&gt;
&lt;li&gt;A broken workflow run?
&lt;/li&gt;
&lt;li&gt;A failed check?
&lt;/li&gt;
&lt;li&gt;Or maybe an impactful update, like a database migration?
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without &lt;strong&gt;clear visibility and actionable insights&lt;/strong&gt;, finding answers feels impossible.  &lt;/p&gt;

&lt;p&gt;Errors don’t exist in isolation—they leave clues scattered across different tools. The challenge is connecting those dots and focusing on the right clues.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The solution: Enforceable best practices&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As a team, we must &lt;strong&gt;always know what’s happening across our toolchains&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;This means:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Best practices must be &lt;strong&gt;enforceable—not just referenced&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Critical steps can’t be optional; they must be &lt;strong&gt;monitored, enforced, and standardized&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Every skipped test, failed check, or bypassed review should trigger &lt;strong&gt;visibility and accountability&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;How can Warestack help you monitor and enforce best practices?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.warestack.com" rel="noopener noreferrer"&gt;Warestack&lt;/a&gt; is a free DevOps tool that helps teams monitor and enforce best practices across events like issues, pull requests, and deployment reviews.  &lt;/p&gt;

&lt;p&gt;We do this in &lt;strong&gt;three simple steps&lt;/strong&gt;:  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Connect your tools&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Integrate tools like &lt;strong&gt;GitHub, Jira, and more&lt;/strong&gt; to access key events as a team directly from Warestack.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Enable best practices to monitor&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Enable and customize pre-built best practices—or suggest new ones!  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Require at least two reviewers per pull request.
&lt;/li&gt;
&lt;li&gt;Enforce conventional commit message formats.
&lt;/li&gt;
&lt;li&gt;All required status checks must pass before merging.&lt;/li&gt;
&lt;li&gt;Deployments must be reviewed by someone other than the requestor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyvyk10cjkbobrdpjq60o.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%2Fyvyk10cjkbobrdpjq60o.png" alt="Example Configuration" width="800" height="537"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Customize rules to match your team’s workflow, and pick severity and minimum assignees! &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%2F7uitgl7dwv12p9th069s.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%2F7uitgl7dwv12p9th069s.png" alt="Customization Example" width="800" height="537"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Monitor violations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Head to the &lt;strong&gt;Monitoring dashboard&lt;/strong&gt; to see flagged violations, complete with severity levels. Access info such as &lt;em&gt;who, when, what&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft45o365e0fsz7hdc6kb2.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%2Ft45o365e0fsz7hdc6kb2.png" alt="Monitoring Dashboard" width="800" height="624"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example: Pull request review&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;PR has no reviewers assigned (minimum required: 2).
&lt;/li&gt;
&lt;li&gt;PR was merged without required reviews.
&lt;/li&gt;
&lt;li&gt;Commit message doesn’t follow the standard format.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everyone on the team can access the dashboard and stay aware of potential production risks.  &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%2F7ntu27d4xkige2h927kt.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%2F7ntu27d4xkige2h927kt.png" alt="PR Review Example" width="800" height="350"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example: Deployment review&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;This deployment was self-approved by the same person who initiated it—a clear bad practice!  &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%2F13rmfmqqwqurnkwvggt2.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%2F13rmfmqqwqurnkwvggt2.png" alt="Deployment Review Example" width="800" height="194"&gt;&lt;/a&gt;  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;What’s Next for Warestack?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We’re currently focusing on enforcement, such as canceling events with unmet conditions. For example, force-cancel a deployment if it was self-approved by the same person who initiated it. This will force the initiator to request the deployment review from a different team member to ensure independent verification. &lt;strong&gt;This ensures accountability and visibility&lt;/strong&gt;. That release will come out soon!&lt;/p&gt;

&lt;p&gt;Also, we will soon support &lt;strong&gt;custom best practices&lt;/strong&gt; and evaluating them against industry standards. Soon, we’ll help you identify if your team’s custom standards align with global best practices.  &lt;/p&gt;

&lt;p&gt;Further, DORA metrics are a key focus for us! Soon, we’ll help you monitor critical metrics like deployment frequency, lead time, and change failure rate and take proactive decisions to prevent issues. For example, if a GitHub workflow run fails, Warestack can automatically move the associated ticket back to "In Progress" and notify the team on Slack!&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Do you like what we are building?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Then we’d love your help!&lt;/strong&gt;&lt;br&gt;
We’re also looking for pilot users!  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No payment is required. &lt;/li&gt;
&lt;li&gt;No hidden commitments. &lt;/li&gt;
&lt;li&gt;Just honest feedback from developers like you.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're creating a community hub where anyone can suggest a best practice.&lt;/p&gt;

&lt;p&gt;If you’re interested, &lt;strong&gt;&lt;a href="//stelios.sotiriadis@warestack.com"&gt;reach out&lt;/a&gt;, and let’s chat!&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;Thanks for reading,&lt;br&gt;&lt;br&gt;
Stelios&lt;/p&gt;

</description>
      <category>github</category>
      <category>bestpractices</category>
      <category>devops</category>
    </item>
    <item>
      <title>Automate GitHub operations with best-practices</title>
      <dc:creator>Stelios Sotiriadis</dc:creator>
      <pubDate>Sun, 08 Dec 2024 10:53:55 +0000</pubDate>
      <link>https://forem.com/steliosot/automate-github-operational-tasks-with-best-practices-1lj</link>
      <guid>https://forem.com/steliosot/automate-github-operational-tasks-with-best-practices-1lj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Thank you for taking the time to read this post! We’re a small team of developers passionate about creating a tool that helps teams seamlessly manage best practices in their daily operations. After speaking with over 50 developers about their challenges, we found a common theme: following best practices consistently can solve critical problems and enable faster, more confident releases. That’s why we built Warestack. Warestack is free for developers and small teams! &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Please try it out and let us know what you think!&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Warestack: Manage every code change with best practices
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Warestack&lt;/code&gt; is a developer tool that automates operational tasks triggered by code changes, highlighting best practices at every step.&lt;/p&gt;

&lt;p&gt;Think of &lt;code&gt;Warestack&lt;/code&gt; as an extra team member dedicated to keeping your team on track. It reminds you of essential tasks and guides you through critical processes like pull request reviews, code merges, and other workflow-driven activities.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does &lt;code&gt;Warestack&lt;/code&gt; work?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Connect your GitHub operations&lt;/strong&gt;: Install the &lt;code&gt;Warestack GitHub App&lt;/code&gt; and import the repositories you need to monitor—all within a single, centralized space.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor key events&lt;/strong&gt;:&lt;code&gt;Warestack&lt;/code&gt; consolidates all workflows and events across your codebase, including issues, pull requests, deployment reviews, and workflow runs.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Best of all, Warestack is free for all developers!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h3&gt;
  
  
  How to Get Started
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Visit &lt;strong&gt;&lt;a href="https://www.warestack.com" rel="noopener noreferrer"&gt;Warestack.com&lt;/a&gt;&lt;/strong&gt; and create an account.&lt;/li&gt;
&lt;li&gt;Install the &lt;code&gt;Warestack GitHub App&lt;/code&gt; and select the repositories you want to monitor.&lt;/li&gt;
&lt;li&gt;Start using &lt;code&gt;Warestack&lt;/code&gt;! &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We recommend importing your past issues, pull requests, and deployment reviews to access everything from your personalized overview page.&lt;/p&gt;




&lt;h3&gt;
  
  
  Your overview page at a glance
&lt;/h3&gt;

&lt;p&gt;Here’s an example of the &lt;code&gt;Warestack overview&lt;/code&gt; page. It offers a unified view of all your workflow runs, even if they’re spread across different repositories. You can see issues, PRs, deployment reviews, and workflow runs from all imported repositories in a single space!&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%2Fa47pq8f4uqwinvehvuxg.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%2Fa47pq8f4uqwinvehvuxg.png" alt="A screenshot of the Warestack overview page, showing a list of workflow runs consolidated from multiple repositories, organized for easy navigation and encouraging best practices in workflow management." width="800" height="692"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If a workflow run fails&lt;/strong&gt;, fix it quickly by identifying the error and reviewing the details. &lt;code&gt;Warestack&lt;/code&gt; ensures you follow best practices in resolving issues efficiently. Open the failed run in the assistant or create an issue.&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%2F13ziha7p1fw19y6butz5.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%2F13ziha7p1fw19y6butz5.png" alt="A screenshot showing a failed workflow run with detailed error messages, providing actionable insights to diagnose and resolve the issue effectively." width="800" height="692"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Simplify issue management with best practices
&lt;/h3&gt;

&lt;p&gt;Let's create an issue! &lt;code&gt;Warestack&lt;/code&gt; automatically generates detailed issues with recommended assignees, labels, and descriptions, aligning with best practices.&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%2Flmt5p069jugsq7u3sfc1.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%2Flmt5p069jugsq7u3sfc1.png" alt="A screenshot of the issue creation feature, showing a newly generated issue with pre-filled details like assignee, labels, and a clear description, following best practices for issue tracking." width="800" height="692"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you decide to use the assistant, &lt;code&gt;Warestack&lt;/code&gt;provides actionable recommendations to resolve issues, ensuring you follow to industry best practices.&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%2F7godfik9t2bdajyzs4he.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%2F7godfik9t2bdajyzs4he.png" alt="A screenshot of Warestack's assistant providing detailed recommendations to address a failed workflow, aligning with best practices for efficient issue resolution." width="800" height="840"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The assistant also helps manage daily tasks such as reviewing pull requests, generating workflows, and onboarding repositories. It ensures you're always up-to-date with the latest changes by indexing your repository's state.&lt;/p&gt;




&lt;h3&gt;
  
  
  Generate workflows with high standards
&lt;/h3&gt;

&lt;p&gt;Let's try an example! Generate a GitHub Action that triggers whenever a user pushes code to a new feature branch. This action will notify your development channel in Slack, following best practices for team collaboration.&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%2Fe1a57ogmcf0s086ouvtx.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%2Fe1a57ogmcf0s086ouvtx.png" alt="A screenshot of Warestack's workflow editor, showcasing an example GitHub Action that sends a Slack notification when a feature branch is updated, ensuring seamless communication." width="800" height="747"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's explore another example. Set up a GitHub Action to run automated tests when a pull request is opened. This ensures code quality by adhering to best practices and providing feedback directly in the pull request comments.&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%2Fpyrc9u6rixh8wol5wtqc.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%2Fpyrc9u6rixh8wol5wtqc.png" alt="A screenshot showing an example GitHub Action in Warestack's editor, designed to trigger automated tests for new pull requests and provide detailed feedback in the comments, following continuous integration best practices." width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Warestack's assistant gives you access to over 10,000 GitHub Actions, recommending the most relevant and widely-used ones based on best practices.&lt;/p&gt;




&lt;h3&gt;
  
  
  There are more!
&lt;/h3&gt;

&lt;p&gt;You can explore our documentation at &lt;a href="https://www.warestack.com/documentation" rel="noopener noreferrer"&gt;https://www.warestack.com/documentation&lt;/a&gt; on how to efficiently create issues and manage PRs and deployment reviews. &lt;/p&gt;

&lt;h3&gt;
  
  
  Help us make it better!
&lt;/h3&gt;

&lt;p&gt;We’re constantly improving Warestack, and your feedback is invaluable. If you encounter a bug or have a feature suggestion, please contact us:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;General Inquiries&lt;/strong&gt;: &lt;a href="//mailto:stelios.sotiriadis@warestack.com"&gt;stelios.sotiriadis@warestack.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Support&lt;/strong&gt;: &lt;a href="//mailto:support@warestack.com"&gt;support@warestack.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Join us on this journey to make DevOps automation smarter, faster, and aligned with the best practices in the industry!&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>tooling</category>
      <category>devops</category>
      <category>devtool</category>
    </item>
    <item>
      <title>Messaging in distributed systems using ZeroMQ</title>
      <dc:creator>Stelios Sotiriadis</dc:creator>
      <pubDate>Wed, 06 Nov 2024 15:20:19 +0000</pubDate>
      <link>https://forem.com/steliosot/messaging-in-distributed-systems-using-zeromq-571g</link>
      <guid>https://forem.com/steliosot/messaging-in-distributed-systems-using-zeromq-571g</guid>
      <description>&lt;h3&gt;
  
  
  Messaging in distributed systems using ZeroMQ
&lt;/h3&gt;

&lt;p&gt;Let's use Python to develop the different messaging patterns.&lt;/p&gt;

&lt;p&gt;You will need to watch the following video to follow the step by step commands.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Take your time; make sure you double-check the commands before you run them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;The following video demonstrates the commands used in this tutorial. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://youtu.be/MgPqctyXXmI" rel="noopener noreferrer"&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%2F72q1powg5pz3s5eca3em.jpg" alt="Watch the video" width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;I run this tutorial on my GCP VM, but feel free to run it locally  ✅&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This tutorial introduces the concepts of sockets in Python3 using ZeroMQ. ZeroMQ is an easy way to develop sockets to allow distributed processes to communicate with each other by sending messages. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In its simplest form, a socket (node) “listens” on a specific IP port, while another socket reaches out to form a connection. Using sockets, we can have on-to-one, one-to-many and many-to-many connection patterns. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The patterns of messaging that we will examine today are the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pair:&lt;/strong&gt; Exclusive, one to one communication, where two peers communicate with each other. The communication is bidirectional and there is no specific state stored in the socket. The server listens on a certain port, and the client connects to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fldq7mdkrqt6x6q3nhrvd.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%2Fldq7mdkrqt6x6q3nhrvd.png" alt="Pair example" width="350" height="100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client – Server:&lt;/strong&gt; A client connects to one or more servers. This pattern allows REQUEST – RESPONSE mode. A client sends a request “zmq.REQ” and receives a reply. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faekuh68gyxc40tzixk8q.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%2Faekuh68gyxc40tzixk8q.png" alt="Client-server example" width="322" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Publish/Subscribe:&lt;/strong&gt; A traditional communication pattern where senders of messages, called publishers, send messages to specific receivers, called subscribers. Messages are published without the knowledge of what or if any subscriber of that knowledge exists. Multiple subscribers subscribe to messages/topics being published by a publisher or one subscriber can connect to multiple publishers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fconl88a8nn1udy6ytlqz.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%2Fconl88a8nn1udy6ytlqz.png" alt="Publish-subscribe example" width="800" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Push and Pull sockets (aka Pipelines):&lt;/strong&gt; Let you distribute messages to multiple workers, arranged in a pipeline. A Push socket will distribute sent messages to its Pull clients evenly. This is equivalent to producer/consumer model, but the results computed by consumer are not sent upstream but downstream to another pull/consumer socket.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcp0fiovck54x622gmdw8.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%2Fcp0fiovck54x622gmdw8.png" alt="Push and pull example" width="795" height="414"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨 &lt;strong&gt;Note:&lt;/strong&gt; Working with Sockets could be tricky, running again and again the same code, using the same port number/same socket, could lead to a connection that “hangs” (the server looks like it is running, but it cannot accept connections). This happens because we did not close and destroy the previous connections correctly. &lt;/p&gt;

&lt;p&gt;The most appropriate way to address this is to close the socket and destroy the ZeroMQ context. Refer to try – catch blocks of Phase 2 and Phase 3 for more details. &lt;/p&gt;

&lt;p&gt;In this tutorial, you might experience such issues, e.g., running multiple times the same server in the same port. If you face hanging problems, you are advised to kill the Python process, clean the TCP port number, and run the server once more (see step 11). &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  Phase 1: Pairing a server to a client
&lt;/h5&gt;

&lt;p&gt;Let us start by creating a new VM, then we will install Python3. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep a copy of the VM internal IP, for this tutorial we will use the internal IP address.

&lt;ol&gt;
&lt;li&gt;Open a new terminal connection and run the following commands (one after the other). The last command installs &lt;a href="https://zeromq.org/" rel="noopener noreferrer"&gt;ZeroMQ&lt;/a&gt;.
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;software-properties-common
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3.8
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;python3-pip
&lt;span class="nv"&gt;$ &lt;/span&gt;pip3 &lt;span class="nb"&gt;install &lt;/span&gt;pyzmq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Type: Y when prompted.&lt;/p&gt;

&lt;p&gt;Many applications these days consist of components that stretch across networks, so messaging is essential. Today we will use TCP for message transferring.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can access your VM using VSC, or you can run the commands using the SSH and edit files with &lt;code&gt;pico&lt;/code&gt;, in my case I will use SSH. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨 Make sure you copy code carefully.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will need to create our first &lt;strong&gt;ZeroMQ server&lt;/strong&gt;, the server will allow binding with only one client at a time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Create a new file called &lt;code&gt;pair-server.py&lt;/code&gt;, then enter the following code. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The code creates a new socket using the &lt;strong&gt;zmq.PAIR&lt;/strong&gt; pattern, then binds the server to a particular IP port (that we already openned in GCP). Note that the server will not stop running until we stop it. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have a look at the comments to understand how this works.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure that you change the ; that is the &lt;strong&gt;internal IP address&lt;/strong&gt; of the GCP VM; the client port should be the same with the server.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# import the library
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="c1"&gt;# Initialize a new context that is the way to create a socket
&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# We will build a PAIR connection
&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAIR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# We create a PAIR server
# Do not worry about this for the moment...
&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LINGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
&lt;span class="c1"&gt;# Create a new socket and "bind" it in the following address
# Make sure you update the address
&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;INTERNAL_VM_ADDRESS&amp;gt;:5555&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# IP:PORT
# Keep the socket alive for ever...
&lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Send a text message to the client (send_string)
&lt;/span&gt;    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Server message to Client&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Receive a message, store it in msg and then print it
&lt;/span&gt;    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Sleep for 1 second, so when we run it, we can see the results
&lt;/span&gt;    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not run the server yet, first let us create the client.&lt;/p&gt;

&lt;p&gt;Create the client and take a minute to examine the comments. I will call it &lt;code&gt;pair-client.py&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure that you change the ; the port should be the same as in the server.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="c1"&gt;# Same as before, initialize a socket
&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAIR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# We create a PAIR server
&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LINGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Connect to the IP that we already bind in the server
&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;INTERNAL_VM_ADDRESS&amp;gt;:5555&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# A counter will help us control our connection
# For example connect until you send 10 messages, then disconnect...
&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello from Client&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;This is a client message to server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Counter: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# Destroy the context socket and then close the connection
&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will need &lt;strong&gt;two&lt;/strong&gt; terminal windows to run the &lt;strong&gt;PAIR&lt;/strong&gt; example. We will run the server on one window and the client on the other. Now, run it as follows.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the server
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 pair-server.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Run the client
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 pair-client.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Examine the output, we just created a new &lt;strong&gt;PAIR&lt;/strong&gt; socket.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The script will terminate when the client completes its connection. Then stop the server (ctrl + c) and kill it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will need to clear the TCP connection before we run it again. To do this, 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;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fuser &lt;span class="nt"&gt;-k&lt;/span&gt; 5555/tcp &lt;span class="c"&gt;# 5555 refers to your port number&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🚨 Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We can run &lt;strong&gt;only one PAIR at a time&lt;/strong&gt;, this mean that we cannot have multiple clients, remember this is a &lt;strong&gt;PAIR&lt;/strong&gt;, the first client will lock the socket.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If we run the server once, and the client twice, the second client will “hang”, this means that the second client it will wait for a new server to connect.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If we want to run the pair more than once, we will need to kill the server and clear the TCP connection.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;PAIRs&lt;/strong&gt; are ideal when a client needs to have exclusive access to a server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can have multiple servers to multiple clients as PAIRs, but we will need to use different PORT numbers for the connections. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Each phase is independent of each other, so, stop the server, clear the TCP ports, and move to the next phase.&lt;/strong&gt; &lt;/p&gt;

&lt;h6&gt;
  
  
  Phase 2: Pairing a server to multiple clients
&lt;/h6&gt;

&lt;p&gt;Let us create a client-server connection, where multiple clients will connect to a single server. This is the most popular messaging pattern.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let’s create a server in the context of &lt;strong&gt;REP-REQ&lt;/strong&gt; (reply to a request) pattern. &lt;/li&gt;
&lt;li&gt;We will call the server &lt;code&gt;rep-server.py&lt;/code&gt;, using port &lt;code&gt;5555&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Try to create a new connection
&lt;/span&gt;    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# We create a REP server
&lt;/span&gt;    &lt;span class="c1"&gt;# Here we set a linger period for the socket
&lt;/span&gt;    &lt;span class="c1"&gt;# Linger 0: no waiting period for new messages
&lt;/span&gt;    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LINGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;INTERNAL_VM_ADDRESS&amp;gt;:5555&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Wait for next request from client
&lt;/span&gt;        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Received request: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
        &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hi from Server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# “ctr+c” to break and close the socket!
&lt;/span&gt;    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will develop two Clients that will be identical in terms of their functionality. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* **Client 1** will send a “Client 1 Hello world” request

* **Client 2** will send a “Client 2 Hello world” request to the server. 
* Let us create a file called `req-client1.py`, then edit as follows, again make sure you change the &amp;lt;INTERNAL_VM_ADDRESS&amp;gt;.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REQ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# We create a REQ client (REQUEST)
&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LINGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;INTERNAL_VM_ADDRESS&amp;gt;:5555&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending request Client 1 &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello from client 1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Received reply &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let us create a copy of this client and edit it accordingly. Run the following command to make a new copy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cp &lt;/span&gt;req-client1.py req-client2.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then edit the &lt;code&gt;req-client2.py&lt;/code&gt; and change &lt;code&gt;client 1&lt;/code&gt; to &lt;code&gt;client 2&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Let's edit the print and socket messages (lines 8 and 9)&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REQ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# We create a REQ client (REQUEST)
&lt;/span&gt;&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LINGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;INTERNAL_VM_ADDRESS&amp;gt;:5555&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending request Client 2 &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello from client 2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Received reply &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run this example, we will need &lt;strong&gt;three&lt;/strong&gt; terminal windows, one for the server and two for the clients. Run the following in the first terminal.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let's start the server
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 rep-server.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Let's start the first client
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 req-client1.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Let's start the second client
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 req-client2.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the output of the windows, we just created two clients talking to one server. You can have as many clients as you want, you will need to make clients, even with different functionalities that connect to one server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🚨 &lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Client – Server is the most widely used pattern, we already used it in class 1 when we installed and ran the Apache HTTP server.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stop the server and clean TCP port 5555&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kill the server: &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;br&gt;
     &lt;code&gt;bash&lt;br&gt;
    $ sudo fuser -k 5555/tcp &lt;br&gt;
&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h6&gt;
  
  
  Phase 3: Pairing a server to a client
&lt;/h6&gt;

&lt;p&gt;The publish – subscribe pattern is a very common way to control broadcasting of data to many clients that are subscribed to a context, in a way that servers send data to one or more clients. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* To run multiple servers, we need to map each server to a PORT number.

* In this pattern, messages are published (broadcasted) without knowing that subscribers exist, or if there are any subscribers of this context. 

* It is the task of the subscribers to make connections and filter out the incoming data.

* We usually say: Subscribers, subscribe to a specific context.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let us first create a simple example. &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* We will create two servers that generate weather data, and one client that it is subscribed to both instances to collect data about a particular context:

* The context is: **Client will only “listen” the context related to New York City weather data (postal code 10001)**.

* The first instance of our server will run in port `5555`.

  * This instance generates a topic with an ID.

  * For testing purposes, the topic represents a postcode (in our example, that is a random value between 9999 and 10005).
  * Each time a topic is generated the server also generates weather data e.g., temperature, that actual forms our message.

* The second instance of our server will run in port `5556` and will provide the same functionality.

* This instance generates similar topics and messages. 

* **The assumption here is that both instances represent sensors that send weather data from various areas in different cities.**

* We will create the server code and make it easy to replicate, as you might noticed the only parameter to change is the PORT number.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Let us create a new file, call it &lt;code&gt;pub_server.py&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* The server will accept two arguments from the command line, that will be the IP and the PORT value.
  * For accepting command line arguments we use the `sys` Python library.

* By this way we can run multiple servers, and each time we run the script we will just have to pass IP and PORT number as arguments to the code. For example:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 pub_server.py &amp;lt;internal-ip&amp;gt; &amp;lt;port&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;This command will instruct python to run a server in specific  and 
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Port value is the first argument from the command line
&lt;/span&gt;    &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Topic is the post code, randomly generated 9999-10005
&lt;/span&gt;        &lt;span class="n"&gt;topic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;9999&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10005&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Let us generate the message data (temperature)
&lt;/span&gt;        &lt;span class="n"&gt;messagedata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;215&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;
        &lt;span class="c1"&gt;# Print the data
&lt;/span&gt;        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%d %d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messagedata&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%d %d %d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messagedata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
         &lt;span class="c1"&gt;# Each sensor generates data each second
&lt;/span&gt;        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new file &lt;code&gt;pub_client.py&lt;/code&gt;. &lt;br&gt;
    * The script accepts three arguments from the command line (that are the IP and the two ports).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;port1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Take port1 from command line
&lt;/span&gt;    &lt;span class="n"&gt;port2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# Take port2 from command line
&lt;/span&gt;    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Collecting updates from weather servers...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;ip&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;port2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;topicfilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;10001&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;  &lt;span class="c1"&gt;# Subscribe to postal code e.g. NYC, 10001
&lt;/span&gt;    &lt;span class="c1"&gt;# Subscribe to topicfilter: 10001, WE CARE ONLY FOR NYC!
&lt;/span&gt;    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setsockopt_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUBSCRIBE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;topicfilter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="c1"&gt;# Lets collect up to 5 subscriptions 
&lt;/span&gt;    &lt;span class="c1"&gt;# Then we will calculate the average of 5 temperatures from NYC
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;update_nbr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messagedata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;total_value&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messagedata&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Topic: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;, message: &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; on port &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;
              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messagedata&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Average messagedata value for topic &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;%s&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; was %dF&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; 
                 &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;topicfilter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;total_value&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;update_nbr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are ready to run our &lt;strong&gt;pub-sub&lt;/strong&gt; application! We will need &lt;strong&gt;three&lt;/strong&gt; terminal windows. In the first terminal run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 pub_server.py &amp;lt;internal-ip&amp;gt; 5555
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt; In the second terminal run:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 pub_server.py &amp;lt;internal-ip&amp;gt; 5556
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Each server generates weather data. For example:

&lt;ul&gt;
&lt;li&gt;The postal code, e.g.: 10001&lt;/li&gt;
&lt;li&gt;The temperate, e.g.: -68&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Let’s run the client to connect and subscribe to data by postal code e.g., 10001 (NYC). Remember the client script subscribes to both server instances. Run the next command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 pub_client.py &amp;lt;internal-ip&amp;gt; 5555 5556 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;When you finish kill the servers (ctrl+z) and clear the TCP ports running the next commands:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fuser &lt;span class="nt"&gt;-k&lt;/span&gt; 5555/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;fuser &lt;span class="nt"&gt;-k&lt;/span&gt; 5556/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h6&gt;
  
  
  Phase 4: Push/Pull: Using a Pipeline pattern**
&lt;/h6&gt;

&lt;p&gt;Push/Pull sockets let you distribute messages to multiple workers, arranged in a pipeline. This is very useful for running code in parallel. A Push socket will distribute messages to its Pull clients evenly, and the clients will send a response to another server, called collector.&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%2Fj9tjfx401hefk20j1gz9.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%2Fj9tjfx401hefk20j1gz9.png" alt="Push pull example" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;This is equivalent to producer/consumer model, but the results computed by consumer are not sent upstream but downstream to another pull/consumer socket.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We will implement the following functionality.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The producer will PUSH random numbers from 0 to 10 to the consumers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Two instances of the same consumer will PULL the numbers and will perform a heavy task.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The task could be any heavy calculation e.g., matrix multiplication.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For simplicity, our “heavy task” will just return the same number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The consumers will PUSH the individual results (heavy task calculations) to a &lt;strong&gt;Result Collector&lt;/strong&gt;, that will aggregate the results.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For simplicity, an instance of the &lt;strong&gt;Result Collector&lt;/strong&gt; will PULL the results and calculate the partial sum of each consumer. We can easily sum the two partial sums if needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let us see a simple example.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Producer generates [1,2,3,4,5].&lt;/li&gt;
&lt;li&gt;Consumer 1 receives [2,4], then calculates a heavy task and forwards results to the Result Collector.&lt;/li&gt;
&lt;li&gt;Consumer 2 receives [1,3,5], then calculates a heavy task and forwards results to the Result Collector.&lt;/li&gt;
&lt;li&gt;The result collector calculates the counts and partial sums e.g.:&lt;/li&gt;
&lt;li&gt;Consumer1[2,4], this means &lt;strong&gt;2&lt;/strong&gt; numbers received from Consumer1 and their sum is &lt;strong&gt;6&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Consumer2[1,3,5], that means &lt;strong&gt;3&lt;/strong&gt; numbers received from this Consumer2 and their sum is &lt;strong&gt;9&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;This example demonstrates the potential of distributed processing for parallel processing.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Firstly, let us create the producer called &lt;code&gt;producer.py&lt;/code&gt; running on port &lt;code&gt;5555&lt;/code&gt; make sure you adapt your .&lt;br&gt;
&lt;/p&gt;

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

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;mysum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;zmq_socket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUSH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;zmq_socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;internal-ip&amp;gt;:5555&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# UPDATE THE IP!
&lt;/span&gt;    &lt;span class="c1"&gt;# Generates 10 numbers
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# Random numbers: 1 to 5
&lt;/span&gt;        &lt;span class="n"&gt;work_message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;zmq_socket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;work_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;work_message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mysum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mysum&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;val&lt;/span&gt;
        &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;mysum&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;producer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create the &lt;code&gt;consumer.py&lt;/code&gt; is as follows. Do not forget to change the two s in code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;heavyTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Perform a heavy task
&lt;/span&gt;    &lt;span class="c1"&gt;# Here we can perform any heavy calculation e.g. i**100+i*200
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="c1"&gt;# For simplicity we return the same value...
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;consumer_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;randrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10005&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I am consumer #%s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumer_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# receive work from producer (port 5555)
&lt;/span&gt;    &lt;span class="n"&gt;consumer_receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# UPDATE THE IP!
&lt;/span&gt;    &lt;span class="n"&gt;consumer_receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;internal-ip&amp;gt;:5555&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# send work to collector (port 5556)
&lt;/span&gt;    &lt;span class="n"&gt;consumer_sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PUSH&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# UPDATE THE IP!
&lt;/span&gt;    &lt;span class="n"&gt;consumer_sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;internal-ip&amp;gt;:5556&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;consumer_receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;consumer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;heavyTask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;consumer_sender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;# Run the consumer
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let us develop the &lt;code&gt;collector.py&lt;/code&gt;, again change the .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pprint&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="c1"&gt;# Pull the results from port 5556 (consumers)
&lt;/span&gt;&lt;span class="n"&gt;results_receiver&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;zmq&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;results_receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tcp://&amp;lt;internal-ip&amp;gt;:5556&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# UPDATE THE IP!
&lt;/span&gt;&lt;span class="n"&gt;collecter_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="n"&gt;asum&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
   &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;results_receiver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;recv_json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;collecter_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# This is how to count and sum items in a dictionary...
&lt;/span&gt;      &lt;span class="n"&gt;collecter_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collecter_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="n"&gt;collecter_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collecter_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
   &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="n"&gt;collecter_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;consumer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;num&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]]&lt;/span&gt;
&lt;span class="n"&gt;pprint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pprint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collecter_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you don’t have an indentation error!&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* Let us run it and examine how the pipeline works.

* We will need **four** terminal windows.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Firstly, we need to run the &lt;code&gt;collector.py&lt;/code&gt;, the collector will be waiting for data to be collected until we start the producer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 collector.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Then, we will start the &lt;strong&gt;consumers one by one&lt;/strong&gt;, run each command in a different terminal window.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 consumer.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Run the same command in another terminal.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 consumer.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Finally, we will start our producer that will start sending data to our pipeline.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;python3 producer.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Well done! 🏁 You used ZeroMQ to develop messaging patterns!&lt;/p&gt;

</description>
      <category>zeromq</category>
      <category>pubsub</category>
      <category>eventdriven</category>
      <category>python</category>
    </item>
  </channel>
</rss>
