<?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: charliemday</title>
    <description>The latest articles on DEV Community by charliemday (@charliemday).</description>
    <link>https://dev.to/charliemday</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%2F398608%2Fc34a28a5-e3ee-466f-8c07-99aff1c1cf60.jpg</url>
      <title>DEV Community: charliemday</title>
      <link>https://dev.to/charliemday</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/charliemday"/>
    <language>en</language>
    <item>
      <title>Django Background Tasks</title>
      <dc:creator>charliemday</dc:creator>
      <pubDate>Thu, 05 Oct 2023 20:03:31 +0000</pubDate>
      <link>https://dev.to/charliemday/django-background-tasks-1bcm</link>
      <guid>https://dev.to/charliemday/django-background-tasks-1bcm</guid>
      <description>&lt;p&gt;Background tasks are processes that run in the background so your server is ready to take further requests. &lt;/p&gt;

&lt;p&gt;Some common use cases for background tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web Scraping&lt;/li&gt;
&lt;li&gt;Heavy data processing&lt;/li&gt;
&lt;li&gt;Image processing&lt;/li&gt;
&lt;li&gt;Multiple 3rd party API calls&lt;/li&gt;
&lt;li&gt;Building Slack-bots (Slack requires a 3 second response)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, if the task takes a long time to complete (e.g. &amp;gt;30 seconds) you probably want to offload it to a background task.&lt;/p&gt;

&lt;p&gt;If you have your Django project set up it's dead easy to get a background tasks up and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Getting Started
&lt;/h2&gt;

&lt;p&gt;We want to install &lt;a href="https://django-q.readthedocs.io/en/latest/" rel="noopener noreferrer"&gt;Django Q&lt;/a&gt; via: &lt;/p&gt;

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

pip install django-q


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

&lt;/div&gt;

&lt;p&gt;Django Q allows us to set up some queues to run in the background. Be sure to run the migrations as well to generate the job models (which you'll see in your admin panel)&lt;/p&gt;

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

python manage.py migrate


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

&lt;/div&gt;

&lt;p&gt;It requires a &lt;strong&gt;broker&lt;/strong&gt; though...&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Setting up Redis
&lt;/h2&gt;

&lt;p&gt;We'll use &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;redis&lt;/a&gt;. This is basically the communication channel between your &lt;strong&gt;django instance&lt;/strong&gt; (normal django) and your &lt;strong&gt;django worker&lt;/strong&gt; (this is your background task/worker). &lt;/p&gt;

&lt;p&gt;You can check if your redis server is running by running:&lt;/p&gt;

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

redis-cli ping


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

&lt;/div&gt;

&lt;p&gt;If not you'll need to follow the &lt;a href="https://redis.io/" rel="noopener noreferrer"&gt;redis&lt;/a&gt; instructions to set up on your system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Setting up the Cluster
&lt;/h2&gt;

&lt;p&gt;The standard django-q configuration will work for us locally but with a couple of changes so we can run this in production as well. Add the following to your base &lt;code&gt;settings.py&lt;/code&gt; file:&lt;/p&gt;

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

REDIS_HOST = os.environ.get("REDIS_HOST", "localhost")
REDIS_PORT = os.environ.get("REDIS_PORT", 6379)
REDIS_DB = os.environ.get("REDIS_DB", 0)
REDIS_PASSWORD = os.environ.get("REDIS_PASSWORD", None)

Q_CLUSTER = {
    "name": "hello-django",
    "workers": 8,
    "recycle": 500,
    "timeout": 60,
    "compress": True,
    "cpu_affinity": 1,
    "save_limit": 250,
    "queue_limit": 500,
    "label": "Django Q",
    "redis": {
        "host": REDIS_HOST,
        "port": REDIS_PORT,
        "db": REDIS_DB,
        "password": REDIS_PASSWORD,
    },
}



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

&lt;/div&gt;

&lt;p&gt;You can play around with the number of &lt;code&gt;workers&lt;/code&gt; - the default is &lt;code&gt;8&lt;/code&gt; and these are the number of instances that can run in parallel with each other. &lt;/p&gt;

&lt;p&gt;We can now actually start running the &lt;strong&gt;cluster&lt;/strong&gt;. Have 2 terminal windows and in 1 have your standard &lt;code&gt;python manage.py runserver&lt;/code&gt; running and in the other run:&lt;/p&gt;

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

python manage.py qcluster


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

&lt;/div&gt;

&lt;p&gt;You now have your cluster running. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Creating our Task
&lt;/h2&gt;

&lt;p&gt;Create a standard API to make a simple &lt;code&gt;POST&lt;/code&gt; request and let's add the task:&lt;/p&gt;

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

from django_q.tasks import async_task
from rest_framework.views import APIView
import time

...

class SimpleTask(APIView):

    def task(self, s = 5):
        print("⏳ Running task")
        # We could call some long running code here
        time.sleep(s)
        print("⌛ Task finished")

    def post(self, request):
        # We can run the task in the background
        async_task(self.task, s=5)
        return Response({
            "message": "Task started"
        })


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

&lt;/div&gt;

&lt;p&gt;We use &lt;code&gt;async_task&lt;/code&gt; to wrap the task. The code will essentially see this and send it to the redis server (which will send it to the cluster) and continue to the response. &lt;/p&gt;

&lt;p&gt;You can place anything in the &lt;code&gt;task&lt;/code&gt; and the response will still be returned in the same amount of time. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Deploying to Production
&lt;/h2&gt;

&lt;p&gt;Having this run in a safe local environment is one thing. Deploying it to a production environment is another. &lt;/p&gt;

&lt;p&gt;We'll be using &lt;a href="https://railway.app/" rel="noopener noreferrer"&gt;Railway&lt;/a&gt; (other than them I'd recommend &lt;a href="https://fly.io/" rel="noopener noreferrer"&gt;Fly.io&lt;/a&gt; or &lt;a href="https://render.com/" rel="noopener noreferrer"&gt;Render&lt;/a&gt; - the principles are the same).&lt;/p&gt;

&lt;p&gt;We want to add a &lt;code&gt;railway.json&lt;/code&gt; file in our Django App with the following:&lt;/p&gt;

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

{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS"
  },
  "deploy": {
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 10
  }
}


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

&lt;/div&gt;

&lt;p&gt;In Railway you want to create &lt;strong&gt;1 Redis database&lt;/strong&gt;, &lt;strong&gt;2 Django Apps&lt;/strong&gt;. In the first Django App you want the &lt;strong&gt;Deploy (Start Command)&lt;/strong&gt; to be:&lt;/p&gt;

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

python manage.py migrate &amp;amp;&amp;amp; gunicorn NAMEOFYOURAPP.wsgi


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

&lt;/div&gt;

&lt;p&gt;And in the second:&lt;/p&gt;

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

python manage.py migrate &amp;amp;&amp;amp; python manage.py qcluster


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

&lt;/div&gt;

&lt;p&gt;You'll want to update the environment variables for both applications to match the &lt;code&gt;REDIS&lt;/code&gt; environment variables (see &lt;strong&gt;Step 2&lt;/strong&gt;), for this I recommend using Railway's &lt;strong&gt;shared variables&lt;/strong&gt;. The end result looks something like:&lt;/p&gt;

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

&lt;p&gt;Think of this mirroring your terminals (the standard Django instance and the new Django qcluster instance)&lt;/p&gt;

&lt;p&gt;To verify this is all working, make a request to your &lt;code&gt;SimpleTask&lt;/code&gt; (you can find the URL if you click on the &lt;code&gt;api&lt;/code&gt; app) and take a look at the &lt;strong&gt;Observability&lt;/strong&gt; tab and you should see your &lt;strong&gt;background task running&lt;/strong&gt; 🎉&lt;/p&gt;

</description>
      <category>django</category>
      <category>python</category>
    </item>
    <item>
      <title>My Stack for Rapid Prototyping ⚡</title>
      <dc:creator>charliemday</dc:creator>
      <pubDate>Tue, 26 Sep 2023 07:29:24 +0000</pubDate>
      <link>https://dev.to/charliemday/my-stack-for-rapid-prototyping-1alg</link>
      <guid>https://dev.to/charliemday/my-stack-for-rapid-prototyping-1alg</guid>
      <description>&lt;p&gt;As a solo developer one of the advantages you have over large incumbents and companies is your ability to rapidly build and test in a real-world environment. &lt;/p&gt;

&lt;p&gt;There are no layers of bureaucracy with single developers (or small groups of developers). You can deploy straight to prod because of the most important factor - you have so much more to gain than to lose. &lt;/p&gt;

&lt;p&gt;With larger companies, this is reversed. So I would lean into this advantage and you can do that by rapidly prototyping applications. Here's my stack of tools that I feel have helped me speed up development - nothing fancy, and all (mostly) free! &lt;/p&gt;

&lt;h2&gt;
  
  
  Frontend
&lt;/h2&gt;

&lt;p&gt;For &lt;strong&gt;landing pages&lt;/strong&gt; I use &lt;a href="https://astro.build/"&gt;Astrobuilt&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the actual &lt;strong&gt;app interface&lt;/strong&gt; I use a &lt;a href="https://github.com/charliemday/hello-frontend"&gt;NextJS Boilerplate&lt;/a&gt; that I've used on previous projects (I don't bother with latest versions because the user doesn't care)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deploying&lt;/strong&gt; the app and landing page I use &lt;a href="https://vercel.com"&gt;Vercel&lt;/a&gt; as it has a free tier to deploy straight from GitHub and site analytics which is a win&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend
&lt;/h2&gt;

&lt;p&gt;Depending on complexity I got for either &lt;a href="https://supabase.com/"&gt;Supabase&lt;/a&gt; (If I have a basic CRUD app)or for more complicated backends I go with a trusty &lt;a href="https://github.com/charliemday/hello-django"&gt;Django Boilerplate&lt;/a&gt; with authentication APIs already setup and a PostgreSQL database.&lt;/p&gt;

&lt;p&gt;Deploying the backend I use &lt;a href="https://railway.app"&gt;Railway&lt;/a&gt; as the interface is really clean and it's significantly cheaper than and (and in my opinion just easier to use than Heroku)&lt;/p&gt;




&lt;p&gt;That's it! Using this I can get a landing page up within 30 minutes and an MVP inside 2 weeks (which is my general target). Would be interesting to hear other people's stacks for rapid prototyping!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
