<?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: Khela Tech</title>
    <description>The latest articles on DEV Community by Khela Tech (@khelatech).</description>
    <link>https://dev.to/khelatech</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4212926%2F90d36624-e43a-4c31-be5b-30819d7da84e.png</url>
      <title>DEV Community: Khela Tech</title>
      <link>https://dev.to/khelatech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/khelatech"/>
    <language>en</language>
    <item>
      <title>Two schedulers, one question: how we keep a 150-job small-business ops platform reliable</title>
      <dc:creator>Khela Tech</dc:creator>
      <pubDate>Wed, 28 Oct 2026 11:18:03 +0000</pubDate>
      <link>https://dev.to/khelatech/two-schedulers-one-question-how-we-keep-a-150-job-small-business-ops-platform-reliable-1l3c</link>
      <guid>https://dev.to/khelatech/two-schedulers-one-question-how-we-keep-a-150-job-small-business-ops-platform-reliable-1l3c</guid>
      <description>&lt;p&gt;Khela Tech builds AI and workflow automation for Canadian small businesses. This is a write-up of one system we run in production: the operations platform behind a Toronto-area pet-boarding business. It is not a product tour. It is the one design decision that kept the system reliable as it grew past 150 scheduled jobs, and the rules that came with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;A boarding business runs on small, repetitive tasks with hard deadlines: booking confirmations by SMS, reminders 48 hours before arrival, invoices, review requests, inventory reorders, client follow-ups, and the email that has to be read and filed into the CRM. None of it is hard on its own. All of it is easy to forget on a busy day, and every miss is a client who did not get told something.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the solution
&lt;/h2&gt;

&lt;p&gt;One Python Flask control plane, backed by PostgreSQL, owns the business logic. Each automation is a scheduled job: one job, one purpose, one log line per run. Today that is 150+ jobs.&lt;/p&gt;

&lt;p&gt;The interesting part is not the jobs. It is deciding &lt;strong&gt;where each job is scheduled&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two schedulers, one question
&lt;/h2&gt;

&lt;p&gt;Every recurring job lives in one of two places, and one question decides which:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Does this job need to run when the app itself is not running?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Yes: the operating system's task scheduler.&lt;/strong&gt; This is the small "infrastructure ring": the watchdog that relaunches the app, the nightly backups, network failover, anything that manages the app or must survive it being down.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No: the in-app scheduler.&lt;/strong&gt; This is the default for everything else: reports, reminders, syncs, monitors. These jobs only make sense when the app is up, and they share its database connection, locks and in-memory state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It sounds obvious. The failure modes when you ignore it are not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A backup job living &lt;em&gt;inside&lt;/em&gt; the app does nothing on exactly the night the app has crashed, which is the night you needed it.&lt;/li&gt;
&lt;li&gt;A reminder job moved &lt;em&gt;out&lt;/em&gt; of the app to "make it independent" loses the shared state and locks it was quietly relying on, and starts double-sending.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the rule is enforced in one direction only: keep the infrastructure ring small and stable, and put every new business job in the app. We do not blanket-migrate one ring into the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  One pane of glass
&lt;/h2&gt;

&lt;p&gt;Two schedulers means two places to look, which is how jobs get forgotten. A read-only dashboard lists both side by side, live: the in-app job list and the OS scheduled tasks, split into the two rings, with last and next run times. When something is late, there is one page to open.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make every job boring to operate
&lt;/h2&gt;

&lt;p&gt;A few habits matter more than any framework choice:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Every job logs, retries and reports.&lt;/strong&gt; A job that fails quietly is worse than one that never existed, because people stop checking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert on staleness, not just on exceptions.&lt;/strong&gt; Some of the worst failures never raise: the job ran, did nothing, and exited 0. A monitor that asks "when did this last do real work?" catches those.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background means background.&lt;/strong&gt; Scheduled tasks run hidden. A console window flashing up on the operator's screen every few minutes is how someone ends up closing the wrong window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A watchdog owns restarts.&lt;/strong&gt; Nobody restarts the app by hand. The watchdog relaunches it, so there is never a second copy running the same 150 jobs twice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plain-English alerts.&lt;/strong&gt; A routine success is one sentence or nothing. Detail is for when a human has to act.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The outcome
&lt;/h2&gt;

&lt;p&gt;One founder runs the business without an operations team. The system does the admin; people do the work that needs a person. When a job breaks, the monitoring says so before a client notices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Stack
&lt;/h2&gt;

&lt;p&gt;Python, Flask, PostgreSQL, the in-app &lt;code&gt;schedule&lt;/code&gt; library, Windows Task Scheduler, Resend for email, OpenPhone for SMS, QuickBooks, Stripe, Google Workspace and Sentry.&lt;/p&gt;




&lt;p&gt;Khela Tech is a Toronto AI automation studio for Canadian small businesses: voice agents, AI agents, workflow automation and custom integrations, each shipped with monitoring and a runbook. More live systems: &lt;a href="https://khelatech.ca/case-studies" rel="noopener noreferrer"&gt;khelatech.ca/case-studies&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>python</category>
      <category>architecture</category>
      <category>smallbusiness</category>
    </item>
  </channel>
</rss>
