<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anubhav Singh</title>
    <description>The latest articles on DEV Community by Anubhav Singh (@xprilion).</description>
    <link>https://dev.to/xprilion</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%2F297538%2F89564ec1-66a1-4564-aa4b-d7adc684377f.jpeg</url>
      <title>DEV Community: Anubhav Singh</title>
      <link>https://dev.to/xprilion</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xprilion"/>
    <language>en</language>
    <item>
      <title>Job Scheduling on Google Cloud Platform</title>
      <dc:creator>Anubhav Singh</dc:creator>
      <pubDate>Thu, 13 Apr 2023 03:56:52 +0000</pubDate>
      <link>https://dev.to/xprilion/job-scheduling-on-google-cloud-platform-h2</link>
      <guid>https://dev.to/xprilion/job-scheduling-on-google-cloud-platform-h2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Job scheduling is like conducting an orchestra; every task must play its part at the right time to create a harmonious symphony of efficiency.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the world of software systems, job scheduling plays a critical role in ensuring efficient task execution and harmonious resource management. In this article, we'll explore what job scheduling is, the different types of scheduled jobs and how to implement job scheduling using different available methods. We'll mostly be focusing on the tools and services available for Job Scheduling on Google Cloud Platform. However, these concepts can be extended to any platform with slight modifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scheduling with System Crons: A Classic Approach
&lt;/h2&gt;

&lt;p&gt;For those who prefer a more traditional approach, system crons can be used for job scheduling. This method involves creating a cron job on a Compute Engine instance or Kubernetes cluster. Although system crons lack some of the features provided by GCP's managed services, they can still be a useful tool for basic scheduling tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: Database Maintenance with System Cron
&lt;/h3&gt;

&lt;p&gt;In this example, we'll create a simple cron job on a Compute Engine instance to perform periodic database maintenance.&lt;/p&gt;

&lt;p&gt;First, SSH into your Compute Engine instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud compute ssh my-instance &lt;span class="nt"&gt;--zone&lt;/span&gt; my-instance-zone
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, open the crontab editor to create a new cron job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following line to the crontab file to schedule a database maintenance script to run every Sunday at 3 AM:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0 3 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; 7 /path/to/your/db-maintenance-script.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save and exit the editor. The cron job is now scheduled to run the &lt;code&gt;db-maintenance-script.sh&lt;/code&gt; script every Sunday at 3 AM.&lt;/p&gt;

&lt;p&gt;Remember that system crons depend on the availability and reliability of your Compute Engine instance. If the instance experiences downtime or other issues, your scheduled tasks may not execute as expected. When using system crons, it's essential to implement monitoring and error handling to maintain the reliability of your scheduling solution.&lt;/p&gt;

&lt;p&gt;Keep in mind that using system crons may require more manual management compared to GCP's managed services. However, they can still be a viable option for simple scheduling tasks that don't require the advanced features provided by GCP's job scheduling components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding Cron Job Timing Parameters
&lt;/h3&gt;

&lt;p&gt;Cron job scheduling is based on a series of timing parameters that determine when a task should be executed. A cron job's timing is represented by a string containing five fields separated by spaces: minute, hour, day of the month, month, and day of the week.&lt;/p&gt;

&lt;p&gt;Each field can have a specific value, a range of values, or a wildcard (*) to represent all possible values. Here's a brief explanation of each field:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minute (0-59)&lt;/strong&gt;: Specifies the minute when the task should be executed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hour (0-23)&lt;/strong&gt;: Specifies the hour when the task should be executed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day of the month (1-31)&lt;/strong&gt;: Specifies the day of the month when the task should be executed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Month (1-12 or JAN-DEC)&lt;/strong&gt;: Specifies the month when the task should be executed. You can use either numeric values or three-letter month abbreviations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Day of the week (0-7 or SUN-SAT)&lt;/strong&gt;: Specifies the day of the week when the task should be executed. Both 0 and 7 represent Sunday. You can use either numeric values or three-letter day abbreviations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some examples of cron job timing parameters and their meanings:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0 3 * * *&lt;/code&gt;: This schedule runs the task every day at 3 AM.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0 3 * * 7&lt;/code&gt;: This schedule runs the task every Sunday at 3 AM.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0 3 1 * *&lt;/code&gt;: This schedule runs the task at 3 AM on the first day of every month.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;*/15 * * * *&lt;/code&gt;: This schedule runs the task every 15 minutes.&lt;/p&gt;

&lt;p&gt;Understanding the cron job timing parameters allows you to create precise schedules for your tasks, ensuring that they run exactly when needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  GCP Job Scheduling Components
&lt;/h2&gt;

&lt;p&gt;GCP provides several key components for job scheduling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/scheduler"&gt;Cloud Scheduler&lt;/a&gt;: A managed cron service for time-based tasks&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/functions"&gt;Cloud Functions&lt;/a&gt;: A serverless platform for event-driven functions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/pubsub"&gt;Cloud Pub/Sub&lt;/a&gt;: A global messaging service for event-driven architectures&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://cloud.google.com/workflows"&gt;Cloud Workflows&lt;/a&gt;: A serverless workflow orchestration service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These components are crucial for creating efficient scheduling solutions. For an in-depth understanding of each component, consult the &lt;a href="https://cloud.google.com/products"&gt;GCP documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduling Strategies: Time-based, Event-based, and Hybrid
&lt;/h3&gt;

&lt;p&gt;GCP offers three primary scheduling strategies, allowing you to select the best fit for your needs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Time-based scheduling&lt;/strong&gt; with Cloud Scheduler: Ideal for tasks that need to run at regular intervals or specific times, such as backups or maintenance jobs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event-based scheduling&lt;/strong&gt; with Cloud Functions and Cloud Pub/Sub: Perfect for tasks that need to be executed in response to specific events, such as user actions or data updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid scheduling&lt;/strong&gt;: A flexible and dynamic job scheduling system that adapts to various scenarios and needs by combining both time-based and event-based approaches.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Best Practices for Job Scheduling in GCP
&lt;/h3&gt;

&lt;p&gt;To ensure optimal performance and reliability, consider the following best practices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring and Logging&lt;/strong&gt;: Utilize tools like &lt;a href="https://cloud.google.com/monitoring"&gt;Cloud Monitoring&lt;/a&gt; and &lt;a href="https://cloud.google.com/logging"&gt;Cloud Logging&lt;/a&gt; to keep a close eye on the performance and progress of your scheduled tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling and Retries&lt;/strong&gt;: Implement error handling and retries in your job scheduling process to maintain system reliability and minimize the impact of failures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource Allocation&lt;/strong&gt;: Leverage GCP tools for load balancing and autoscaling to optimize resource usage and maintain system performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Considerations&lt;/strong&gt;: Follow best practices and use GCP's security features to protect your scheduled tasks and ensure the overall security of your system.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Enhancing Job Scheduling with Google Cloud Operations Suite
&lt;/h2&gt;

&lt;p&gt;Google Cloud Operations Suite, formerly known as Stackdriver, is a comprehensive suite of tools that helps developers monitor, troubleshoot, and optimize their applications on GCP. While not a job scheduling tool itself, Cloud Operations Suite can significantly enhance job scheduling by providing insights into application performance, resource usage, and potential issues.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: With Cloud Monitoring, you can set up custom dashboards to track metrics, logs, and traces from your job scheduling components such as Cloud Functions, Cloud Scheduler, and Cloud Pub/Sub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging&lt;/strong&gt;: Cloud Logging enables you to store, search, and analyze log data from your scheduled tasks, making it easier to identify and resolve issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Reporting&lt;/strong&gt;: Cloud Error Reporting automatically detects and reports errors from your applications, allowing you to quickly identify and resolve issues affecting your scheduled tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace&lt;/strong&gt;: Cloud Trace helps you analyze the performance of your applications by collecting and visualizing latency data from your job scheduling components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By integrating Google Cloud Operations Suite with your job scheduling components, you can gain valuable insights into your application's performance and optimize your scheduling strategy for better efficiency and reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Streamline Event-driven Job Scheduling with Eventarc
&lt;/h2&gt;

&lt;p&gt;Eventarc is a GCP service that simplifies event-driven job scheduling by allowing you to route events from various sources to Google Cloud services or custom targets. It enables you to create event-driven applications that can react to changes in your environment, such as new files being added to Cloud Storage or updates in a Firestore database.&lt;/p&gt;

&lt;p&gt;With Eventarc, you can create event-based job scheduling solutions that trigger Cloud Functions, Cloud Run services, or custom webhooks based on specific events. For example, you could set up a Cloud Function to process new images uploaded to Cloud Storage or trigger a Cloud Run service to handle updates in a Firestore database.&lt;/p&gt;

&lt;p&gt;Here's how you can create a trigger using Eventarc:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Enable the Eventarc API:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud services &lt;span class="nb"&gt;enable &lt;/span&gt;eventarc.googleapis.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Create an Eventarc trigger:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud eventarc triggers create my-trigger &lt;span class="nt"&gt;--destination-run-service&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-cloud-run-service &lt;span class="nt"&gt;--destination-run-region&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;my-region &lt;span class="nt"&gt;--event-filters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"type=google.cloud.pubsub.topic.v1.messagePublished"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates an Eventarc trigger named &lt;code&gt;my-trigger&lt;/code&gt; that listens for messages published to a Cloud Pub/Sub topic and sends the event to the specified Cloud Run service in the given region.&lt;/p&gt;

&lt;p&gt;By leveraging Eventarc in your job scheduling strategy, you can create more dynamic, event-driven applications that automatically react to changes in your environment, improving efficiency and reducing the need for manual intervention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Examples of Job Scheduling in GCP
&lt;/h2&gt;

&lt;p&gt;To better understand the practical applications of GCP's scheduling strategies, let's dive into some real-world examples:&lt;/p&gt;

&lt;h3&gt;
  
  
  Time-based Example: Automated Backups
&lt;/h3&gt;

&lt;p&gt;Automate backups of your system using Cloud Scheduler to ensure data protection and recovery. To create a Cloud Scheduler job that triggers a backup, use the following &lt;code&gt;gcloud&lt;/code&gt; command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud scheduler &lt;span class="nb"&gt;jobs &lt;/span&gt;create http my-backup-job &lt;span class="nt"&gt;--schedule&lt;/span&gt; &lt;span class="s2"&gt;"0 1 * * *"&lt;/span&gt; &lt;span class="nt"&gt;--http-method&lt;/span&gt; POST &lt;span class="nt"&gt;--uri&lt;/span&gt; https://example.com/backup &lt;span class="nt"&gt;--oidc-service-account-email&lt;/span&gt; my-sa@example.iam.gserviceaccount.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;my-backup-job&lt;/code&gt; is a backup job that runs daily at 1 AM, making a POST request to &lt;code&gt;https://example.com/backup&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event-based Example: Real-time Data Processing
&lt;/h3&gt;

&lt;p&gt;Implement real-time data processing using Cloud Functions and Cloud Pub/Sub. For instance, you can create a Cloud Function that processes incoming data and a Cloud Pub/Sub topic to trigger the function.&lt;/p&gt;

&lt;p&gt;First, deploy the Cloud Function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud functions deploy processData &lt;span class="nt"&gt;--runtime&lt;/span&gt; nodejs14 &lt;span class="nt"&gt;--trigger-topic&lt;/span&gt; my-data-topic &lt;span class="nt"&gt;--entry-point&lt;/span&gt; processDataFunction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;processData&lt;/code&gt; is the function that processes incoming data, triggered by the &lt;code&gt;my-data-topic&lt;/code&gt; Cloud Pub/Sub topic.&lt;/p&gt;

&lt;p&gt;Then, publish a message to the Cloud Pub/Sub topic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud pubsub topics publish my-data-topic &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s1"&gt;'{"data": "your-data-here"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command publishes a message containing data to the &lt;code&gt;my-data-topic&lt;/code&gt; topic, which triggers the &lt;code&gt;processData&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;The code for this function has not been included in this blog for sake of focus on the topic. You can check it out in this &lt;a href="https://gist.github.com/xprilion/b2b763e11c3d4a51a90e2dfa8f49210d"&gt;Github Gist&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hybrid Example: Inventory Management
&lt;/h3&gt;

&lt;p&gt;Manage inventory with hybrid scheduling, using time-based tasks for restocking and event-based tasks for real-time updates. For instance, you can create a Cloud Scheduler job for periodic restocking and a Cloud Function triggered by Cloud Pub/Sub for processing real-time inventory updates.&lt;/p&gt;

&lt;p&gt;First, create the Cloud Scheduler job for restocking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud scheduler &lt;span class="nb"&gt;jobs &lt;/span&gt;create http restock-job &lt;span class="nt"&gt;--schedule&lt;/span&gt; &lt;span class="s2"&gt;"0 2 * * 1"&lt;/span&gt; &lt;span class="nt"&gt;--http-method&lt;/span&gt; POST &lt;span class="nt"&gt;--uri&lt;/span&gt; https://example.com/restock &lt;span class="nt"&gt;--oidc-service-account-email&lt;/span&gt; my-sa@example.iam.gserviceaccount.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;restock-job&lt;/code&gt; is a restocking job that runs every Monday at 2 AM, making a POST request to &lt;code&gt;https://example.com/restock&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, deploy the Cloud Function for real-time inventory updates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud functions deploy updateInventory &lt;span class="nt"&gt;--runtime&lt;/span&gt; nodejs14 &lt;span class="nt"&gt;--trigger-topic&lt;/span&gt; inventory-updates &lt;span class="nt"&gt;--entry-point&lt;/span&gt; updateInventoryFunction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, &lt;code&gt;updateInventory&lt;/code&gt; is the function that processes real-time inventory updates, triggered by the &lt;code&gt;inventory-updates&lt;/code&gt; Cloud Pub/Sub topic.&lt;/p&gt;

&lt;p&gt;Finally, publish a message to the Cloud Pub/Sub topic for inventory updates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud pubsub topics publish inventory-updates &lt;span class="nt"&gt;--message&lt;/span&gt; &lt;span class="s1"&gt;'{"update": "your-update-here"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command publishes a message containing an inventory update to the &lt;code&gt;inventory-updates&lt;/code&gt; topic, which triggers the &lt;code&gt;updateInventory&lt;/code&gt; function.&lt;/p&gt;

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

&lt;p&gt;GCP offers a robust set of tools for efficient job scheduling, ensuring optimal resource usage, scalability, and fault tolerance. By selecting the appropriate scheduling strategy and following best practices, developers can craft robust and efficient scheduling solutions tailored to their specific needs. With a deeper understanding of GCP job scheduling, you can unlock the full potential of your applications and tackle even the most complex systems.&lt;/p&gt;

&lt;p&gt;Happy scheduling!&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>jobscheduling</category>
      <category>eventdriven</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Python Websockets SSL with Let's Encrypt</title>
      <dc:creator>Anubhav Singh</dc:creator>
      <pubDate>Thu, 05 Jan 2023 16:35:35 +0000</pubDate>
      <link>https://dev.to/xprilion/python-websockets-ssl-with-lets-encrypt-4o48</link>
      <guid>https://dev.to/xprilion/python-websockets-ssl-with-lets-encrypt-4o48</guid>
      <description>&lt;p&gt;This tutorial is an explanation of my gist &lt;a href="https://gist.github.com/xprilion/ceab48ec77a70be1d403e396170991e6" rel="noopener noreferrer"&gt;Python Websockets SSL with Let's Encrypt&lt;br&gt;
&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With the launch of HTML5 in 2008, a technology that immediately took off in popularity was WebSockets. According to W3C, the basic definition of a Websocket is - an interface that enables web applications to maintain bidirectional communications with server-side processes.&lt;/p&gt;

&lt;p&gt;In this short tutorial, I'll be showing you how you can host a WebSocket server with SSL enabled on it. This allows your socket server to run on an HTTPS address. &lt;/p&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;We'll be working with &lt;code&gt;asyncio&lt;/code&gt; library and for WebSocket server implementation will be using the &lt;code&gt;websockets&lt;/code&gt; library.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;asyncio&lt;/code&gt; library comes pre-packaged with Python distributions since Python 3.4. To install &lt;code&gt;websockets&lt;/code&gt; library, you can 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;pip &lt;span class="nb"&gt;install &lt;/span&gt;websockets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we'll be looking to how to generate the SSL certificate files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate certificate and keyfile using Let's Encrypt
&lt;/h2&gt;

&lt;p&gt;Before you can enable SSL on your WebSocket being run by a Python script, you'll have to generate certificate files for your domain. &lt;/p&gt;

&lt;p&gt;The basic gist of this step is to fetch Let's Encrypt signed certficiates for your domain and store them on your server where the Python WebSocket script is running.&lt;/p&gt;

&lt;p&gt;Here's a great quick tutorial on &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-use-certbot-standalone-mode-to-retrieve-let-s-encrypt-ssl-certificates-on-ubuntu-20-04" rel="noopener noreferrer"&gt;How To Use Certbot Standalone Mode to Retrieve Let's Encrypt SSL Certificates on Ubuntu 20.04&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make certificate files accessible
&lt;/h2&gt;

&lt;p&gt;After generating the files correctly, you need to make them accessible to the current user who runs the Python WebSocket script. &lt;/p&gt;

&lt;p&gt;In the previous step, if &lt;code&gt;certbot&lt;/code&gt; stored your certificate files at &lt;code&gt;/etc/letsencrypt/live/your_domain&lt;/code&gt; location, you should be able to see 4 files when you perform an &lt;code&gt;ls&lt;/code&gt; on the folder -&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;ls&lt;/span&gt; /etc/letsencrypt/live/your_domain
cert.pem  chain.pem  fullchain.pem  privkey.pem  README
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To change the owner of the certificate files, 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 chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-u&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt; /etc/letsencrypt/live/your_domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, ensure that the right permissions are applied to the folder:&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 chmod&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; 400 /etc/letsencrypt/live/your_domain
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're now good to read these files from the Python WebSocket script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create server script
&lt;/h2&gt;

&lt;p&gt;While your WebSocket server script will differ from the most barebones implementation, here's one for you -&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;socket_server.py&lt;/code&gt;. Then, make all the necessary imports.&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="c1"&gt;#!/usr/bin/env python
&lt;/span&gt;
&lt;span class="c1"&gt;# WS server example that synchronizes state across clients
&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;websockets&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, let us configure the SSL for this script, as shown below -&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="n"&gt;ssl_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SSLContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PROTOCOL_TLS_SERVER&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Generate with Lets Encrypt, chown to current user and 400 permissions
&lt;/span&gt;&lt;span class="n"&gt;ssl_cert&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/live/your_domain/fullchain.pem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;ssl_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/live/your_domain/privkey.pem&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;ssl_context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_cert_chain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ssl_cert&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;keyfile&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ssl_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code configures the script to run a TLS server with the certificates available in the folder generated by &lt;code&gt;certbot&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Next, we define the functions that shall be used to notify clients of the socket server and to get information from them.&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="n"&gt;STATE&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;value&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="n"&gt;USERS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;state_event&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;state&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;STATE&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;users_event&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;users&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="p"&gt;)})&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify_state&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;USERS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# asyncio.wait doesn't accept an empty list
&lt;/span&gt;        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;state_event&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify_users&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;USERS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="c1"&gt;# asyncio.wait doesn't accept an empty list
&lt;/span&gt;        &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;users_event&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, we need to add functions that register and unregister clients from the WebSocket.&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="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notify_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;USERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notify_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This done, let us implement a function that gets state update requests from clients and performs it.&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="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# register(websocket) sends user_event() to websocket
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;state_event&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;websocket&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;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&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;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;minus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;STATE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&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="mi"&gt;1&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notify_state&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;action&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="n"&gt;STATE&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&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="mi"&gt;1&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;notify_state&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;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unsupported event: {}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;unregister&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we run the server.&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="n"&gt;start_server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;websockets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6789&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ssl_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_event_loop&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run_until_complete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_event_loop&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run_forever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How you expose the server to the internet, I shall leave that on your use case. However, you can explore this tutorial on &lt;a href="https://websockets.readthedocs.io/en/stable/howto/nginx.html" rel="noopener noreferrer"&gt;Websockets - Deploy behind nginx&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implement a client page
&lt;/h2&gt;

&lt;p&gt;To test the above WebSocket script, you can spin up your own client script or feel free to use the &lt;a href="https://gist.github.com/xprilion/ceab48ec77a70be1d403e396170991e6#file-socket_client-html" rel="noopener noreferrer"&gt;socket_client.html&lt;/a&gt; file I've provided.&lt;/p&gt;

&lt;p&gt;Make sure to update the following line in the client file to point to your live server -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;websocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;wss://localhost:6789/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that we're using the &lt;code&gt;wss://&lt;/code&gt; protocol here instead of &lt;code&gt;ws://&lt;/code&gt; protocol which is popularly found on other tutorials on the internet.&lt;/p&gt;

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

&lt;p&gt;This was my attempt at explaining the gist I put out more than an year back. Hope it helps you go through the process easier than how I had first written it.&lt;/p&gt;

&lt;p&gt;Make sure to leave me feedback on how this blog went!&lt;/p&gt;

</description>
      <category>emptystring</category>
    </item>
  </channel>
</rss>
