• Skip to main content
  • Skip to footer

Dyspatch

  • Products
      • Overview
      Features
      • No-code email builder
      • Email collaboration
      • SMS builder
      • AMP for Email
      • Template localization
      • Expert services
      • Partners & integrations
      •  
      Find your fit
      • Tools for email Designers
      • Dyspatch for translators
      • Email production for Marketers
      • Resources for email Developers
      Sendwithus Logo
      • Overview
      • Analytics
      • A/B testing
      • Triggered emails
  • Pricing
  • Case studies
  • Resources
    • Blog
    • Free templates
    • Webinars
    • Ebooks, guides, & reports
  • Company
    • About us
    • Careers
    • Contact us
  • Login
    • Dyspatch
    • Sendwithus
Get a demo

Task Monitoring Using Redis

By Dyspatch | September 7, 2014 | Categories: News
redis blog
⏱ 3 minute read

We’ve started using Redis a lot and it’s been great. We’ve already used it to improve performance in our analytics pipeline, and to power our usage-based billing system.

Most recently we’ve written a leaner, faster version of our background task monitoring system based on Redis. Here’s how we did it…

The Goal

All background tasks use a simple Producer-Consumer model, built on Amazon SQS and Python. Our goal is to track and identify periods of low/high task throughput and adjust the number of available consumers accordingly.

Transactional email traffic can be very bursty, so it’s important that we’re able to monitor and provision workers in real-time.

At any time, we need to know:

  • How many workers are currently working on Task X
  • How long has it been since Task X was last completed

Using Redis Hashes

We use Redis Hashes to track this information. A Redis Hash looks like this:

HASH_KEY:
    FIELD_ONE: 0
    FIELD_TWO: 14
    FIELD_THREE: 6

There are two important features of hashes that make them great for our use case:

  1. Hash values can be incremented/decremented atomically using HINCRBY
  2. Undefined fields have an implicit value of 0

This means that we can safely increment any field in a Hash even if it hasn’t been set yet. This is great because we never need to initialize the data structure when adding new fields, and if we ever need to we can delete a Hash and start over.

Tracking Active Tasks

We use an ‘ACTIVE_TASKS’ Hash to track how many tasks are currently active.

ACTIVE_TASKS:
    TASK_A: 7
    TASK_B: 0

When a worker starts performing Task X, it will increment the TASK_X field by 1. Once it has completed the task, it will decrement the field by 1.

We can then use HGET TASK_X to fetch the number of Task X being performed at any given moment.

In the above example, there are 7 active TASK_As, and 0 active TASK_Bs. All other task types are undefined and have an implicit value of 0.

Tracking Idle Time

We use a second Hash called ‘IDLE_SINCE’ to track how long it’s been since a particular task was performed.

IDLE_SINCE:
    TASK_A: 1410080563
    TASK_B: 1410080042

This Hash stores a Unix Timestamp for each task type, indicating when the most recent task of that type was completed.

In the example above:

  • TASK_A was last completed at 2014/09/07 9:02:43
  • TASK_B was last completed at 2017/09/07 8:54:02

Maintaining these values is pretty simple — every time a worker completes a task, it sets the timestamp to the current time.

Detecting Idle Tasks

Now for the tricky part – detecting when tasks are idle.

To do this, we fetch values from both Hashes for a specific task and run the following pseudo-code:

if ACTIVE_TASKS.TASK_X > 0:
    return NOT_IDLE
if (NOW - IDLE_SINCE:TASK_X) < IDLE_THRESHOLD:
    return NOT_IDLE
return IDLE

The value of IDLE_THRESHOLD defines how long a task must not be performed before being considered “idle”.

This threshold can be whatever you need – we use different values depending on the task type.

What it Looks Like in Python

Here’s some code to get you started (Gist):

def start_task(task_type):
    redis.HINCRBY('ACTIVE_TASKS', task_type, 1)

def stop_task(task_type):
    with redis.MULTI:
        redis.HSET('IDLE_SINCE', task_type, now())
        redis.HINCRBY('ACTIVE_TASKS', task_type, -1)

def get_active_tasks(task_type):
    return redis.HGET('ACTIVE_TASKS', task_type) or 0

def is_task_idle(task_type, idle_threshold_seconds):
    with redis.MULTI:
        active_tasks = redis.HGET('ACTIVE_TASKS', task_type) or 0
        idle_since = redis.HGET('IDLE_SINCE', task_type) or 0
   
    if active_tasks > 0:
        return False
    return (now() - idle_since) > idle_threshold_seconds

Notes and Warnings

Undefined tasks are infinitely idle. This is because both get_active_tasks and idle_since will return 0 if the task has not yet been seen. In our use case this behaviour is ideal, but it may require more thought in other situations.

Use Multi/Exec to prevent some race conditions. The Redis MULTI command can turn a series of commands into one atomic operation. We use it to prevent race conditions between idle checks and tasks starting/stopping.

Always call stop_task. It’s easy to run into problems if a worker calls start_task and fails to call stop_task. Make sure you’re wrapping your tasks properly and using intelligent error handling.

Protect against negative counts. It’s also possible to call stop_task too many times, giving a negative ACTIVE_TASKS count. Our production code has some additional checks in place to catch and prevent this scenario, as well as log appropriate warnings.

Garbage collection. One of the hardest parts about using Redis is key management and garbage collection. Fortunately this solution only uses two keys: ACTIVE_TASKS and IDLE_SINCE. So garbage collection is super easy.

Resetting tracking data. Because we have protection in place against negative ACTIVE_TASKS values, the Hashes used can be cleared at any time – calling stop_task on an empty Hash will simply set its value to 0.

Dyspatch

With Dyspatch, you can build engaging, interactive emails, without having to write code. By leveraging a custom modular email design system, non-technical teams can deploy beautiful, on-brand campaigns faster and achieve greater operational efficiency.

  • Facebook
  • Twitter
  • Instagram
  • LinkedIn
  • YouTube

    Related Posts

  • Introducing Dyspatch by Sendwithus
  • Dyspatch Wins 2018 MarTech Breakthrough Award for Best Email Marketing Solution for Enterprise
  • A/B Test with Confidence.js
Tags: Sendwithus Archives
Share this post:
  • Facebook
  • Pinterest
  • Twitter
  • Linkedin
LET’S CHAT!

Why wait? Take your email marketing to the next level today.

Get a demo

5307 Victoria Drive #899
Vancouver, BC
V5P 3V6

548 Market Street,
San Francisco, California
94104 US

  • Phone 1-877-458-9231
  • Email us@dyspatch.io
    security@dyspatch.io
  • Facebook
  • Twitter
  • Instagram
  • LinkedIn
  • YouTube

Get the latest email strategies, tips, and trends right to your inbox.

About Dyspatch

  • About us
  • Careers
  • Contact us
  • Pricing
  • Press & Media
  • Release Notes

Find your fit

  • Tools for email Designers
  • Dyspatch for translators
  • Email production for Marketers
  • Resources for email Developers

Features

  • Dyspatch overview
  • No-code email builder
  • Email collaboration
  • Email template localization
  • AMP for Email
  • Sample AMP email templates
  • Expert Services
  • Sendwithus Overview
  • Agency Program

Email resources

  • Blog
  • Webinars
  • Ebooks Guides & Reports
  • HTML email templates
  • Knowledge base
  • Figma email builder
  • The Dyspatch Block gallery

Integrations

  • Partners & Integrations directory
  • Email builder for Braze
  • Email builder for Iterable
  • Email builder for Salesforce Marketing Cloud
  • Email builder for Pardot
  • Email builder for SendGrid
  • Email builder for Marketo
  • Email builder for HubSpot
  • Email builder for Oracle Eloqua

Dyspatch respectfully acknowledges the Lekwungen and W̱SÁNEĆ People, whose unceded territories we live and work on. We would also like to express our gratitude to all of the Coast Salish people as we continue to work and live as guests on their lands.

We recognize that acts of colonization created many inequities for First Nations, Inuit, and Métis people. As a company, we acknowledge that we have a responsibility to work towards reconciliation and to remain open to suggestions and consultations, especially with Indigenous communities.

Privacy policy    |    Terms of service    |    Web accessibility    |    Cookie policy    |    Usage    |    Sitemap

Copyright © 2025 Techdrop Labs Inc. All Rights Reserved.


Features & Functionality
Starter Teams Teams+
Universal styling  ✓  ✓  ✓
Drag and drop email builder  ✓  ✓  ✓
Custom code editor  ✓  ✓  ✓
Custom fonts  ✓  ✓  ✓
Device specific elements  ✓  ✓  ✓
Version history  ✓  ✓  ✓
Social media link settings  ✓  ✓  ✓
Commenting  ✓  ✓  ✓
Live previews  ✓  ✓  ✓
Dark mode previews  ✓  ✓  ✓
Litmus testing  ✓  ✓  ✓
Custom merge fields  ✓  ✓  ✓
Image hosting  ✓  ✓  ✓
Brand & legal compliance guardrails  ✓  ✓  ✓
User role permissions  ✓  ✓  ✓
ESP logic  ✓  ✓  ✓
Code Export  ✓  ✓  ✓
AMP Email Support  ✓  ✓  ✓
Approval Workflows  ✓  ✓  ✓
API Access  ✓  ✓  ✓
User Management –  ✓  ✓
Translation (via Smartling) – –  ✓
Export via API – –  ✓
Localizations – –  ✓
Account Manager – –  ✓
Premium Support – –  ✓
SLA – –  ✓
Premium SAML SSO – –  ✓
Custom Themes – –  ✓
Workspaces – –  ✓
Design / AMP Services – –  ✓
Pricing $149/mo $499/mo Custom
Get a demo

Get a quote