<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Tech With Husnain]]></title><description><![CDATA[Tech With Husnain]]></description><link>https://husnainali.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 14 Oct 2026 06:07:07 GMT</lastBuildDate><atom:link href="https://husnainali.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[From API Calls to Production: 6 LLM Problems Every AI Engineer Should Know]]></title><description><![CDATA[If you've only built a chatbot using the OpenAI API, you probably haven't faced these problems yet.
But once you start building real-world LLM applications, you'll realize the AI model is only one sma]]></description><link>https://husnainali.hashnode.dev/from-api-calls-to-production-6-llm-problems-every-ai-engineer-should-know</link><guid isPermaLink="true">https://husnainali.hashnode.dev/from-api-calls-to-production-6-llm-problems-every-ai-engineer-should-know</guid><category><![CDATA[LLM AI Applications]]></category><category><![CDATA[Production RAG]]></category><category><![CDATA[Backend System Design Engineering]]></category><dc:creator><![CDATA[Husnain Ali]]></dc:creator><pubDate>Fri, 31 Jul 2026 05:53:53 GMT</pubDate><content:encoded><![CDATA[<p><em>If you've only built a chatbot using the OpenAI API, you probably haven't faced these problems yet.</em></p>
<p>But once you start building <strong>real-world LLM applications</strong>, you'll realize the AI model is only one small part of the system.</p>
<p>Recently, I came across these six questions that senior engineers often discuss:</p>
<ul>
<li><p>What happens when the LLM call times out?</p>
</li>
<li><p>How do you stop users from burning hundreds of dollars in tokens?</p>
</li>
<li><p>What if your vector database retrieves the wrong information?</p>
</li>
<li><p>How do you cache an AI that gives different answers every time?</p>
</li>
<li><p>What do you log when someone says, "The answer was wrong"?</p>
</li>
<li><p>Your API returned <strong>200 OK</strong>, but the AI still gave a useless answer. Now what?</p>
</li>
</ul>
<p>At first, these questions sounded complicated.</p>
<p>After understanding them, I realized they are actually <strong>software engineering problems</strong>, not AI problems.</p>
<p>Let's understand each one in the simplest way possible.</p>
<h2>1. What happens when the LLM call times out?</h2>
<p>Imagine your backend sends a request to GPT.</p>
<pre><code class="language-text">User
   │
   ▼
Backend
   │
   ▼
OpenAI API
</code></pre>
<p>Normally, the model responds within a few seconds.</p>
<p>But sometimes the model takes too long.</p>
<p>After waiting for 30 or 60 seconds, your backend stops waiting and returns an error.</p>
<p>This is called a <strong>timeout</strong>.</p>
<p>The important thing to understand is:</p>
<blockquote>
<p>Your backend stopped waiting, but the LLM might still be generating a response.</p>
</blockquote>
<p>Now imagine the user clicks <strong>Generate</strong> again.</p>
<p>Instead of one expensive request, you now have <strong>two requests</strong> running at the same time.</p>
<p>That means higher cost and unnecessary work.</p>
<h3>How companies handle it</h3>
<p>Instead of making the user wait forever, they usually:</p>
<ul>
<li><p>Run the LLM request in the background.</p>
</li>
<li><p>Give the user a job ID.</p>
</li>
<li><p>Let the frontend check whether the result is ready.</p>
</li>
<li><p>Retry only when it's safe.</p>
</li>
</ul>
<p>This makes the application much more reliable.</p>
<h2>2. How do you stop one user from spending $400 in tokens?</h2>
<p>Every API call costs money.</p>
<p>Now imagine someone writes a script like this:</p>
<pre><code class="language-python">while True:
    ask_ai()
</code></pre>
<p>Thousands of requests later, your OpenAI bill becomes much larger than expected.</p>
<p>One careless or malicious user can consume a huge portion of your budget.</p>
<h3>How companies handle it</h3>
<p>They don't allow unlimited usage.</p>
<p>Common techniques include:</p>
<ul>
<li><p>Rate limiting (for example, 20 requests per minute)</p>
</li>
<li><p>Daily request limits</p>
</li>
<li><p>Monthly token limits</p>
</li>
<li><p>Maximum context size</p>
</li>
<li><p>Budget alerts for unusual spending</p>
</li>
</ul>
<p>These limits protect both the application and the company.</p>
<h2>3. Where does the Vector Database live, and what if it retrieves the wrong information?</h2>
<p>Many LLM applications use <strong>RAG (Retrieval-Augmented Generation)</strong>.</p>
<p>The flow usually looks like this:</p>
<pre><code class="language-text">User Question
      │
      ▼
Vector Database
      │
Relevant Documents
      │
      ▼
LLM
      │
      ▼
Final Answer
</code></pre>
<p>The Vector Database stores document embeddings and helps find the most relevant information.</p>
<p>But sometimes it retrieves the wrong documents.</p>
<p>Imagine asking:</p>
<blockquote>
<p>"What is our vacation policy?"</p>
</blockquote>
<p>Instead of retrieving the vacation policy, it retrieves the parking policy.</p>
<p>The LLM doesn't know it's the wrong document.</p>
<p>It simply answers confidently based on what it received.</p>
<p>This is why people often say:</p>
<blockquote>
<p><strong>Garbage in → Garbage out.</strong></p>
</blockquote>
<h3>How companies handle it</h3>
<p>They improve retrieval by:</p>
<ul>
<li><p>Splitting documents into better chunks</p>
</li>
<li><p>Using better embedding models</p>
</li>
<li><p>Combining keyword search with vector search</p>
</li>
<li><p>Re-ranking retrieved documents</p>
</li>
<li><p>Refusing to answer when confidence is too low</p>
</li>
</ul>
<p>The goal isn't to make the LLM smarter.</p>
<p>The goal is to provide it with <strong>better information</strong>.</p>
<h2>4. How do you cache something that gives different answers every time?</h2>
<p>Normally, caching is simple.</p>
<p>If someone asks:</p>
<blockquote>
<p>What is 2 + 2?</p>
</blockquote>
<p>The answer is always <strong>4</strong>.</p>
<p>So we can save the answer and reuse it later.</p>
<p>But LLMs don't always behave like that.</p>
<p>Ask:</p>
<blockquote>
<p>"Write me a motivational quote."</p>
</blockquote>
<p>Today, you may get one answer.</p>
<p>Tomorrow, you may get a completely different one.</p>
<p>Both are correct.</p>
<p>That's because LLMs are <strong>non-deterministic</strong>.</p>
<h3>So what do companies cache?</h3>
<p>Instead of caching everything, they cache only things that are expected to stay the same.</p>
<p>For example:</p>
<ul>
<li><p>Document embeddings</p>
</li>
<li><p>Vector search results</p>
</li>
<li><p>Language translations</p>
</li>
<li><p>Text classification</p>
</li>
<li><p>PDF summaries</p>
</li>
</ul>
<p>They usually avoid caching creative tasks like stories, poems, or jokes because users expect fresh responses.</p>
<p>The idea is simple:</p>
<blockquote>
<p>Cache predictable work. Don't cache creativity.</p>
</blockquote>
<h2>5. What do you log when someone says, "The answer was wrong"?</h2>
<p>In traditional software, debugging is usually straightforward.</p>
<p>If the application crashes, you look at the error logs.</p>
<p>But AI applications are different.</p>
<p>The system may work perfectly, yet still produce a bad answer.</p>
<p>Now imagine a user says:</p>
<blockquote>
<p>"The chatbot gave me the wrong refund policy."</p>
</blockquote>
<p>How do you investigate?</p>
<h3>Companies log the entire AI journey.</h3>
<p>Instead of logging only errors, they also save things like:</p>
<ul>
<li><p>The user's question</p>
</li>
<li><p>The system prompt</p>
</li>
<li><p>Retrieved documents</p>
</li>
<li><p>Model name</p>
</li>
<li><p>Temperature</p>
</li>
<li><p>Token usage</p>
</li>
<li><p>Response time</p>
</li>
<li><p>Final AI response</p>
</li>
</ul>
<p>This allows developers to replay the request and understand what happened.</p>
<p>Maybe the wrong document was retrieved.</p>
<p>Maybe the prompt had an issue.</p>
<p>Maybe the model hallucinated.</p>
<p>Without logs, finding the real cause becomes almost impossible.</p>
<h2>6. Your monitoring says <strong>200 OK</strong>, but users still get nonsense.</h2>
<p>This is one of the biggest differences between traditional software and AI applications.</p>
<p>Imagine your backend returns:</p>
<pre><code class="language-text">HTTP 200 OK
</code></pre>
<p>Normally, that means everything worked.</p>
<p>But in AI systems, <strong>200 OK only means the request was processed successfully.</strong></p>
<p>It does <strong>not</strong> guarantee the answer is correct.</p>
<p>For example:</p>
<p>User asks:</p>
<blockquote>
<p>"What is the capital of Pakistan?"</p>
</blockquote>
<p>AI replies:</p>
<blockquote>
<p>"London."</p>
</blockquote>
<p>Technically:</p>
<ul>
<li><p>API worked</p>
</li>
<li><p>Server didn't crash</p>
</li>
<li><p>Model responded</p>
</li>
</ul>
<p>Everything looks healthy.</p>
<p>But the answer is obviously wrong.</p>
<h3>How companies handle it</h3>
<p>They monitor more than just server health.</p>
<p>They also look at AI quality.</p>
<p>Some common approaches include:</p>
<ul>
<li><p>👍 / 👎 feedback buttons</p>
</li>
<li><p>Checking whether answers match the retrieved documents</p>
</li>
<li><p>Using another LLM to review responses</p>
</li>
<li><p>Monitoring how users interact after receiving an answer</p>
</li>
</ul>
<p>Good AI monitoring measures <strong>whether the answer helped the user</strong>, not just whether the server responded successfully.</p>
<h2>Final Thoughts</h2>
<p>Building an LLM application is much more than calling an API.</p>
<p>Most production challenges are actually software engineering problems:</p>
<ul>
<li><p>Handling failures</p>
</li>
<li><p>Controlling costs</p>
</li>
<li><p>Retrieving the right information</p>
</li>
<li><p>Caching intelligently</p>
</li>
<li><p>Logging useful data</p>
</li>
<li><p>Measuring answer quality</p>
</li>
</ul>
<p>Understanding these concepts won't just help you build better AI applications it will also help you in backend and system design interviews.</p>
<p>The AI model is important.</p>
<p>But the engineering around it is what makes an AI application reliable.</p>
]]></content:encoded></item><item><title><![CDATA[Automated Website & Server Monitoring with Django, Celery, Redis and WebSockets]]></title><description><![CDATA[Introduction
In today's digital landscape, website and server uptime is critical. Downtime can lead to lost revenue, poor user experience, and damaged reputation. To address this, I built Service Monitoring Pro—a Django-based web application that con...]]></description><link>https://husnainali.hashnode.dev/automated-website-and-server-monitoring-with-django-celery-redis-and-websockets</link><guid isPermaLink="true">https://husnainali.hashnode.dev/automated-website-and-server-monitoring-with-django-celery-redis-and-websockets</guid><category><![CDATA[ServiceMonitoring]]></category><category><![CDATA[Django]]></category><category><![CDATA[celery]]></category><category><![CDATA[Redis]]></category><category><![CDATA[websockets]]></category><category><![CDATA[#ServerMonitoring]]></category><category><![CDATA[WebsiteMonitoring]]></category><dc:creator><![CDATA[Husnain Ali]]></dc:creator><pubDate>Sat, 08 Mar 2025 05:18:55 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>In today's digital landscape, <strong>website and server uptime</strong> is critical. Downtime can lead to <strong>lost revenue, poor user experience, and damaged reputation</strong>. To address this, I built <strong>Service Monitoring Pro</strong>—a <strong>Django-based web application</strong> that continuously monitors websites and servers,notifies users (using emails) when downtime occurs, and provides an alert dashboard.</p>
<p>In this article, I’ll walk you through how I built this app using <strong>Django, Celery, Redis, and Docker</strong>.🚀</p>
<h2 id="heading-monitoring-mechanism">Monitoring Mechanism</h2>
<p>The system is designed to monitor websites and servers using asynchronous background tasks. It works as follows:</p>
<ol>
<li><p><strong>Website Monitoring</strong>: The system periodically sends HTTP requests to configured websites and checks for responses.</p>
</li>
<li><p><strong>Server Monitoring</strong>: It utilizes ping commands to determine server availability.</p>
</li>
<li><p><strong>Failure Detection</strong>: If a website or server fails to respond within a set threshold, an alert is triggered.</p>
</li>
<li><p><strong>Alert System</strong>: Email notifications are sent to the user when a service goes down.</p>
</li>
<li><p><strong>Real-time Updates</strong>: Using WebSockets, the dashboard reflects live status updates of monitored services.</p>
</li>
</ol>
<h2 id="heading-notification-system">Notification System</h2>
<p>Timely alerts are essential in server and website monitoring. Our system ensures that users receive instant notifications through:</p>
<ul>
<li><p><strong>Email Alerts</strong>: Whenever a service becomes unresponsive, an email is sent with details of the failure.</p>
</li>
<li><p><strong>Dashboard Alerts</strong>: A real-time status update appears on the dashboard to keep users informed at all times.</p>
</li>
</ul>
<h2 id="heading-implementation-details">Implementation Details</h2>
<h2 id="heading-models-for-storing-website-data">Models for Storing Website Data</h2>
<p>Create a model to store the websites and servers that we want to monitor. Each entry will store the URL or server address, the status (whether it's up or down), and the frequency at which we want to check it. Here is the model code:</p>
<pre><code class="lang-plaintext">from django.db import models
from django.contrib.auth.models import User
from django.utils.timezone import now

class Website(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    url = models.URLField(unique=True)
    status = models.CharField(max_length=10, default="UNKNOWN")
    interval = models.IntegerField(choices=INTERVAL_CHOICES, default=60) 
    last_checked = models.DateTimeField(auto_now=True)
    monitoring_type=models.CharField(max_length=50,default="server")

    def __str__(self):
        return self.url
</code></pre>
<p><strong>Explanation:</strong></p>
<ul>
<li><p><strong>url</strong>: This field stores the URL or address of the website or server.</p>
</li>
<li><p><strong>status</strong>: This field holds the current status of the website (e.g., "UP", "DOWN").</p>
</li>
<li><p><strong>interval</strong>: Defines how frequently the system should check the website (e.g., every 1 minute, every 5 minutes).</p>
</li>
<li><p><strong>last_checked</strong>: The timestamp of the last time the website was checked.</p>
</li>
<li><p><strong>monitoring_type</strong>: Whether we are monitoring a website or server.</p>
</li>
</ul>
<h3 id="heading-celery-for-asynchronous-task-execution">Celery for Asynchronous Task Execution</h3>
<p>To check the website’s or server’s status at regular intervals, we will use <strong>Celery</strong>, a powerful asynchronous task queue. Celery helps run periodic tasks in the background, ensuring that the system can check the website without blocking the user’s workflow.</p>
<p>Creating a file <a target="_blank" href="http://celery.py"><code>celery.py</code></a> in your Django project directory:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> os
<span class="hljs-keyword">from</span> celery <span class="hljs-keyword">import</span> Celery
<span class="hljs-keyword">from</span> celery.schedules <span class="hljs-keyword">import</span> crontab
<span class="hljs-keyword">from</span> datetime <span class="hljs-keyword">import</span> timedelta

<span class="hljs-comment"># Set Django settings for Celery</span>
os.environ.setdefault(<span class="hljs-string">"DJANGO_SETTINGS_MODULE"</span>, <span class="hljs-string">"process_monitoring.settings"</span>)

app = Celery(<span class="hljs-string">"process_monitoring"</span>)

<span class="hljs-comment"># Load configuration from Django settings</span>
app.config_from_object(<span class="hljs-string">"django.conf:settings"</span>, namespace=<span class="hljs-string">"CELERY"</span>)

<span class="hljs-comment"># Make sure Celery is using Redis</span>
app.conf.broker_url = os.getenv(<span class="hljs-string">"CELERY_BROKER_URL"</span>, <span class="hljs-string">"redis://redis:6379/0"</span>)

<span class="hljs-comment"># Discover tasks in installed Django apps</span>
app.autodiscover_tasks()

<span class="hljs-comment"># Define periodic tasks using Celery Beat</span>
app.conf.beat_schedule = {
    <span class="hljs-string">'check-websites-every-30-sec'</span>: {
        <span class="hljs-string">'task'</span>: <span class="hljs-string">'monitoring.tasks.check_30_sec'</span>,
        <span class="hljs-string">'schedule'</span>: timedelta(seconds=<span class="hljs-number">30</span>),
    },
    <span class="hljs-string">'check-websites-every-1-min'</span>: {
        <span class="hljs-string">'task'</span>: <span class="hljs-string">'monitoring.tasks.check_1_min'</span>,
        <span class="hljs-string">'schedule'</span>: timedelta(minutes=<span class="hljs-number">1</span>),
    },
    <span class="hljs-string">'check-websites-every-2-min'</span>: {
        <span class="hljs-string">'task'</span>: <span class="hljs-string">'monitoring.tasks.check_2_min'</span>,
        <span class="hljs-string">'schedule'</span>: timedelta(minutes=<span class="hljs-number">2</span>),
    },
    <span class="hljs-string">'check-websites-every-5-min'</span>: {
        <span class="hljs-string">'task'</span>: <span class="hljs-string">'monitoring.tasks.check_5_min'</span>,
        <span class="hljs-string">'schedule'</span>: timedelta(minutes=<span class="hljs-number">5</span>),
    },
}
</code></pre>
<p>This code sets up <strong>Celery</strong> for managing periodic tasks in a Django project, specifically for monitoring website statuses at different intervals. It configures Celery with Redis as the message broker, enabling asynchronous task execution in the background without affecting the main application’s performance. The periodic tasks are defined using <strong>Celery Beat</strong>, which allows tasks like <code>check_30_sec</code>, <code>check_1_min</code>, <code>check_2_min</code>, and <code>check_5_min</code> to run at intervals of 30 seconds, 1 minute, 2 minutes, and 5 minutes, respectively. This configuration ensures that website monitoring occurs automatically at the specified intervals, providing real-time status updates to users.</p>
<p>Create a periodic task to check the website’s status at the interval defined in the <code>Website</code> model. In <a target="_blank" href="http://tasks.py"><code>tasks.py</code></a></p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> socket
<span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> logging
<span class="hljs-keyword">from</span> django.utils.timezone <span class="hljs-keyword">import</span> now
<span class="hljs-keyword">from</span> django.core.mail <span class="hljs-keyword">import</span> send_mail
<span class="hljs-keyword">from</span> django.conf <span class="hljs-keyword">import</span> settings
<span class="hljs-keyword">from</span> celery <span class="hljs-keyword">import</span> shared_task
<span class="hljs-keyword">from</span> .models <span class="hljs-keyword">import</span> Website
<span class="hljs-keyword">from</span> alert.models <span class="hljs-keyword">import</span> Alert
<span class="hljs-keyword">import</span> monitoring.utils <span class="hljs-keyword">as</span> utils

logger = logging.getLogger(__name__)



<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_websites</span>(<span class="hljs-params">interval</span>):</span>
    websites = Website.objects.filter(interval=interval)
    logger.info(<span class="hljs-string">f"Checking <span class="hljs-subst">{websites.count()}</span> websites for <span class="hljs-subst">{interval}</span>-second interval"</span>)

    <span class="hljs-keyword">for</span> website <span class="hljs-keyword">in</span> websites:
        monitoring_type=website.monitoring_type

        <span class="hljs-keyword">if</span> monitoring_type==<span class="hljs-string">"website"</span>:
            website_status=utils.check_website_status(website.url)
            <span class="hljs-keyword">if</span> website.status!=website_status:
                utils.send_alert(website,website_status)
            website.status=website_status
            website.last_checked=now()
            website.save()
            <span class="hljs-keyword">continue</span>
        <span class="hljs-keyword">elif</span> monitoring_type==<span class="hljs-string">"server"</span>:
            hostname = website.url.replace(<span class="hljs-string">"http://"</span>, <span class="hljs-string">""</span>).replace(<span class="hljs-string">"https://"</span>, <span class="hljs-string">""</span>).split(<span class="hljs-string">"/"</span>)[<span class="hljs-number">0</span>]
            new_status=utils.check_server_status(hostname,website.url)
            <span class="hljs-keyword">if</span> website.status != new_status:
                utils.send_alert(website, new_status)
            website.status = new_status
            website.last_checked = now()
            website.save()
            <span class="hljs-keyword">continue</span>
        <span class="hljs-keyword">elif</span> monitoring_type==<span class="hljs-string">"both"</span>:
            hostname = website.url.replace(<span class="hljs-string">"http://"</span>, <span class="hljs-string">""</span>).replace(<span class="hljs-string">"https://"</span>, <span class="hljs-string">""</span>).split(<span class="hljs-string">"/"</span>)[<span class="hljs-number">0</span>]
            new_status_server=utils.check_server_status(hostname,website.url)
            new_status_website=utils.check_website_status(website.url)
            new_status=<span class="hljs-string">""</span>
            <span class="hljs-keyword">if</span> new_status_server==<span class="hljs-string">"UP"</span> <span class="hljs-keyword">and</span> new_status_website==<span class="hljs-string">"UP"</span>:
                new_status=<span class="hljs-string">"UP"</span>
            <span class="hljs-keyword">else</span>:
                new_status=<span class="hljs-string">"DOWN"</span>
            <span class="hljs-keyword">if</span> website.status!=new_status:
                utils.send_alert(website,new_status)
            website.status=new_status
            website.last_checked=now()
            website.save()
    <span class="hljs-keyword">return</span> <span class="hljs-string">f"Checked <span class="hljs-subst">{websites.count()}</span> websites for <span class="hljs-subst">{interval}</span>-second interval"</span>

<span class="hljs-comment"># 6️⃣ CELERY TASKS (Scheduled Checks)</span>
<span class="hljs-meta">@shared_task</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_30_sec</span>():</span>
    <span class="hljs-keyword">return</span> check_websites(<span class="hljs-number">30</span>)

<span class="hljs-meta">@shared_task</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_1_min</span>():</span>
    <span class="hljs-keyword">return</span> check_websites(<span class="hljs-number">60</span>)

<span class="hljs-meta">@shared_task</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_2_min</span>():</span>
    <span class="hljs-keyword">return</span> check_websites(<span class="hljs-number">120</span>)

<span class="hljs-meta">@shared_task</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_5_min</span>():</span>
    <span class="hljs-keyword">return</span> check_websites(<span class="hljs-number">300</span>)
</code></pre>
<p>This <a target="_blank" href="http://tasks.py"><code>tasks.py</code></a> file defines periodic Celery tasks for checking the status of websites and servers at different intervals. The <code>check_websites</code> function queries the <code>Website</code> model to fetch websites based on their monitoring interval. It checks the status of each website or server (depending on the <code>monitoring_type</code>) by calling helper functions from <code>utils</code>. If there is a change in status (e.g., from UP to DOWN), it triggers an alert using the <code>send_alert</code> function. The four Celery tasks (<code>check_30_sec</code>, <code>check_1_min</code>, <code>check_2_min</code>, and <code>check_5_min</code>) are scheduled to run at 30-second, 1-minute, 2-minute, and 5-minute intervals, respectively, ensuring continuous monitoring.</p>
<p>The <a target="_blank" href="http://utils.py"><code>utils.py</code></a> file provides functions for monitoring website and server health:</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> socket
<span class="hljs-keyword">import</span> subprocess
<span class="hljs-keyword">import</span> logging
<span class="hljs-keyword">from</span> django.utils.timezone <span class="hljs-keyword">import</span> now
<span class="hljs-keyword">from</span> django.core.mail <span class="hljs-keyword">import</span> send_mail
<span class="hljs-keyword">from</span> django.conf <span class="hljs-keyword">import</span> settings
<span class="hljs-keyword">from</span> alert.models <span class="hljs-keyword">import</span> Alert
logger = logging.getLogger(__name__)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServerChecking</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_server_reachable</span>(<span class="hljs-params">self,hostname</span>):</span>
        <span class="hljs-keyword">try</span>:
            output = subprocess.run([<span class="hljs-string">"ping"</span>, <span class="hljs-string">"-n"</span>, <span class="hljs-string">"2"</span>, hostname], capture_output=<span class="hljs-literal">True</span>, text=<span class="hljs-literal">True</span>, timeout=<span class="hljs-number">5</span>)
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Reply from"</span> <span class="hljs-keyword">in</span> output.stdout
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>


    <span class="hljs-comment"># 2️⃣ PORT CHECK FUNCTION (Checks if HTTP/HTTPS are Running)</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">is_port_open</span>(<span class="hljs-params">self,hostname, port</span>):</span>
        <span class="hljs-keyword">try</span>:
            <span class="hljs-keyword">with</span> socket.create_connection((hostname, port), timeout=<span class="hljs-number">5</span>):
                <span class="hljs-keyword">return</span> <span class="hljs-literal">True</span>
        <span class="hljs-keyword">except</span> (socket.timeout, socket.error):
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>

    <span class="hljs-comment"># 3️⃣ WEBSITE STATUS CHECK FUNCTION</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_website_status</span>(<span class="hljs-params">self,url</span>):</span>
        <span class="hljs-keyword">try</span>:
            response = requests.get(url, timeout=<span class="hljs-number">5</span>)
            <span class="hljs-keyword">return</span> response.status_code <span class="hljs-keyword">not</span> <span class="hljs-keyword">in</span> [<span class="hljs-number">502</span>, <span class="hljs-number">503</span>, <span class="hljs-number">504</span>]
        <span class="hljs-keyword">except</span> requests.RequestException:
            <span class="hljs-keyword">return</span> <span class="hljs-literal">False</span>

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_website_status</span>(<span class="hljs-params">url</span>):</span>
    status=<span class="hljs-string">""</span>
    <span class="hljs-keyword">try</span>:
        response = requests.get(url, timeout=<span class="hljs-number">5</span>)  <span class="hljs-comment"># Set timeout to avoid long delays</span>
        <span class="hljs-keyword">if</span> response.status_code&gt;=<span class="hljs-number">200</span> <span class="hljs-keyword">and</span> response.status_code&lt;<span class="hljs-number">400</span>:
            status=<span class="hljs-string">"UP"</span>
            <span class="hljs-keyword">return</span> status
        <span class="hljs-keyword">else</span>:
            status=<span class="hljs-string">"DOWN"</span>
            <span class="hljs-keyword">return</span> status
    <span class="hljs-keyword">except</span> requests.exceptions.ConnectionError:
        status=<span class="hljs-string">"DOWN"</span>
        <span class="hljs-keyword">return</span> status
    <span class="hljs-keyword">except</span> requests.exceptions.Timeout:
        status=<span class="hljs-string">"DOWN"</span>
        <span class="hljs-keyword">return</span> status
    <span class="hljs-keyword">except</span> requests.exceptions.RequestException:
        status=<span class="hljs-string">"DOWN"</span>
        <span class="hljs-keyword">return</span> status


<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">check_server_status</span>(<span class="hljs-params">hostname,url</span>):</span>
    check=ServerChecking()
    server_up = check.is_server_reachable(hostname)
    port_80_open = check.is_port_open(hostname, <span class="hljs-number">80</span>)
    port_443_open = check.is_port_open(hostname, <span class="hljs-number">443</span>)
    website_up = check.check_website_status(url)
    new_status = <span class="hljs-string">"UP"</span> <span class="hljs-keyword">if</span> server_up <span class="hljs-keyword">and</span> website_up <span class="hljs-keyword">and</span> (port_80_open <span class="hljs-keyword">or</span> port_443_open) <span class="hljs-keyword">else</span> <span class="hljs-string">"DOWN"</span>
    <span class="hljs-keyword">return</span> new_status

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_alert</span>(<span class="hljs-params">website, status</span>):</span>
    message = <span class="hljs-string">f"Your server hosting <span class="hljs-subst">{website.url}</span> is currently <span class="hljs-subst">{status}</span>."</span>
    Alert.objects.create(user=website.user, url=website.url, status=status, message=message, is_read=<span class="hljs-literal">False</span>)

    <span class="hljs-keyword">if</span> status == <span class="hljs-string">"DOWN"</span>:
        <span class="hljs-keyword">try</span>:
            send_alert_email(website.url,website.user.email)
            logger.info(<span class="hljs-string">f"Email alert sent for <span class="hljs-subst">{website.url}</span>"</span>)
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            logger.error(<span class="hljs-string">f"Failed to send alert email for <span class="hljs-subst">{website.url}</span>: <span class="hljs-subst">{e}</span>"</span>)

<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">send_alert_email</span>(<span class="hljs-params">website_url,email</span>):</span>
    subject = <span class="hljs-string">"⚠️ Website Server Down Alert"</span>
    message = <span class="hljs-string">f"The website Server <span class="hljs-subst">{website_url}</span> is currently DOWN. Please check it immediately!"</span>
    from_email = settings.DEFAULT_FROM_EMAIL
    recipient_list = [email]  <span class="hljs-comment"># Change this to the user's email</span>

    <span class="hljs-keyword">try</span>:
        send_mail(subject, message, from_email, recipient_list)
        logger.info(<span class="hljs-string">f"Alert email sent for <span class="hljs-subst">{website_url}</span>"</span>)
    <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
        logger.error(<span class="hljs-string">f"Failed to send email for <span class="hljs-subst">{website_url}</span>: <span class="hljs-subst">{e}</span>"</span>)
</code></pre>
<ol>
<li><p><strong>ServerChecking Class</strong>:</p>
<ul>
<li><p><code>is_server_reachable</code>: Pings the server to check if it's reachable.</p>
</li>
<li><p><code>is_port_open</code>: Checks if HTTP (port 80) or HTTPS (port 443) is open.</p>
</li>
<li><p><code>check_website_status</code>: Checks if a website is accessible via a GET request.</p>
</li>
</ul>
</li>
<li><p><strong>check_website_status</strong>: A function that checks website accessibility and returns <code>"UP"</code> or <code>"DOWN"</code> based on the status code or errors.</p>
</li>
<li><p><strong>check_server_status</strong>: Combines the checks from <code>ServerChecking</code> to assess the server and website status, returning <code>"UP"</code> or <code>"DOWN"</code>.</p>
</li>
<li><p><strong>send_alert</strong>: Creates an alert and sends an email notification if the website's status is <code>"DOWN"</code>.</p>
</li>
<li><p><strong>send_alert_email</strong>: Sends an email alert to the user about the website being down.</p>
</li>
</ol>
<p>In essence, the file monitors the health of websites/servers and sends notifications if issues are detected.</p>
<p>Want to check out the code? Here’s the <a target="_blank" href="https://github.com/Husnain-Ali-24/servicemonitoringpro">GitHub Repo</a>.</p>
]]></content:encoded></item></channel></rss>