Intellligent Job Scheduling Using AI

How my new project interprets user-specified task schedules without cron or libraries such as rufus and whenever

Obie Fernandez
5 min readJust now

As the author of the book Patterns of Application Development Using AI, I’m always on the lookout for innovative ways to leverage the power of AI in my projects. This past weekend, while working on a new version of Ahhlife, my popular daily journaling app, I encountered an opportunity to let AI take the reins in scheduling the recurring prompt emails sent to users. In this blog post, I’ll share the approach I took and the code that made it possible, showcasing the ideas from my book in action.

Ahhlife is designed to help users maintain a daily journaling habit by sending them email prompts at their preferred schedule. In exisiting versions of the app, scheduling these prompts involves a combination of cron jobs, background workers, and complex conditional logic. However, with the help of my Raix library and the concepts from my book, I was able to streamline the process and let AI handle the heavy lifting.

…for now, this AI-based approach, as computationally inefficient as it is let me rewrite a traditionally complicated part of the Ahhlife logic from scratch in about an hour using TDD.

The key component in this AI-driven scheduling approach is the ScheduleCheck class. This class encapsulates the logic for determining whether it's time to send a user their daily prompt email based on their specified schedule and the current time. Here’s a slightly simplified version of that class.

class ScheduleCheck
include Raix::ChatCompletion
include Raix::FunctionDispatch

attr_accessor :user

function :should_send_email, "Time to send a new email?", send: { type: "boolean" } do |params|
user.prompt! if params[:send]
end

SYSTEM_PROMPT = <<~PROMPT
Your job is to determine if it is time to send the user an email based
on the current time and their stated schedule preference.
Compare the current date and time to the user's stated schedule.
Is it currently within one hour of their stated schedule?
PROMPT

def initialize(user:)
self.user = user
transcript << { system: SYSTEM_PROMPT }
transcript << { system: "It is now #{Time.now.in_time_zone(user.timezone.presence).strftime('%A, %B %d, %Y %I:%M %p')}" }
transcript << { system: "User was last sent email at #{user.last_prompted_at.in_time_zone(user.timezone.presence).strftime('%A, %B %d, %Y %I:%M %p')}" }
transcript << { user: "My desired schedule is #{user.schedule.presence || 'daily at 8am'}." }
end

def call
chat_completion
end

def max_tokens
100
end

def model
"openai/gpt-4o"
end
en

The ScheduleCheck class leverages the power of AI through the Raix library, which provides a seamless interface for integrating AI capabilities into Ruby applications. By including Raix::ChatCompletion and Raix::FunctionDispatch, the class gains the ability to engage in chat-based interactions with an AI model and dispatch functions based on the AI's responses.

The should_send_email tool function is defined using the function macro provided by Raix. This implementation of the function takes a boolean parameter send and triggers the user's prompt email if the AI determines that it's time to send the email.

The initialize method sets up the context for the AI by providing relevant information such as the current time, the user's last prompt timestamp, and their desired schedule. This context is crucial for the AI to make an informed decision about whether to send the prompt email.

When the call method is invoked, it initiates a chat completion with the AI model, passing along the context and the user's schedule preference. The AI model, powered by OpenAI's GPT-4o, analyzes the provided information and determines whether it's within one hour of the user's desired schedule. If the AI concludes that it's time to send the email, it invokes the should_send_email function with send set to true, triggering the prompt email to be sent to the user.

Execution cost at the scale of this project is negligible, about $0.000465 (USD) per check, despite using the relatively expensive GPT4o model. It would be less expensive if I used GPT4o-mini, but I didn’t find it to be as reliable in my testing, especially with edge cases. I suspect it can be made to work, but I didn’t want to invest the time.

At some point in the future, if this new version of Ahhlife becomes very popular I might need to take a different more cost-effective approach. But for now, this AI-based approach, as computationally inefficient as it is let me rewrite a traditionally complicated part of the Ahhlife logic from scratch in about an hour using TDD.

To ensure the reliability and accuracy of this AI-driven scheduling approach, I wrote comprehensive RSpec tests that cover various scenarios, including different user schedules, time zones, and edge cases. These tests give me confidence that the AI is making the right decisions and sending prompt emails at the appropriate times, even with extraordinary specifications like “only on Memorial Day”.

context "when the user makes an unusual schedule" do
before do
user.update(schedule: "only on Memorial Day")
end

it 'prompts the user on Memorial Day' do
Timecop.freeze(Time.zone.parse("2024-05-27 09:05:00")) do # Memorial Day
expect(user).to receive(:prompt!)
subject.call
end
end

If you’re wanting to experiment with this approach in your own project, here’s another couple of associated components that make it come together.

class RecurringPromptJob < ApplicationJob
queue_as :default

def perform
User.active.needs_prompting.each do |user|
ScheduleCheck.new(user: user).call
end
end
end

class User < ApplicationRecord
# only relevant parts of the User class included here
attribute :schedule, :string, default: "daily at 8am"

scope :active, -> { where(disabled: false) }
scope :needs_prompting, -> { where(last_prompted_at: nil).or(where("last_prompted_at < ?", 24.hours.ago)) }

This is just one example of how the concepts and techniques from my book can be applied in real-world projects to unlock the potential of AI in application development. By embracing AI and incorporating it into our development workflows, we can build smarter, more efficient, and more user-centric applications.

If you’re interested in learning more about how to harness the power of AI in your own projects, be sure to check out Patterns of Application Development Using AI. The book is packed with practical insights, code examples, and best practices that will help you navigate the exciting world of AI-driven development.

Stay tuned for more blog posts where I’ll share additional examples and experiences from my journey of integrating AI into my applications. Until then, happy coding!

--

--

Obie Fernandez

CEO of RCRDSHP, Published Author, and Software Engineer. Chief Consultant at MagmaLabs. Electronic Music Producer/DJ. Dad. ❤️‍🔥Mexico City ❤️‍🔥 LatinX (he/him