Today, I'm here to introduce the latest update to the Oxygen.jl. It's been almost a year since my last post, and I've been steadily working on incorporating your feedback and implementing new features to enhance the development experience.
In this post, I'll specifically discuss the most recent addition to the framework: Cron Scheduling. This feature allows you to schedule recurring tasks effortlessly for both endpoints and standalone functions, using the same Cron expressions we're all familiar with.
Additionally, I'll briefly cover the most significant updates that have been introduced since last time. The latest version offers a range of improvements designed to help you build more robust and versatile applications.
JSON serialization & deserialization (customizable):
- This package has always supported automatic JSON serialization and deserialization for request and response data. But now you can also define your own serializers and deserializers by using middleware functions.
- Added support for Cron scheduling, which makes it easy to schedule recurring tasks to run at specific intervals for both endpoints and functions.
- Added the ability to create tasks that repeat at specified intervals, making it easy to schedule and manage recurring tasks within your application.
- Middleware functions enable the creation of custom workflows to intercept incoming requests and outgoing responses in a specific order. They can be set at the application, router, and route layers using the middleware keyword argument, combining and executing the middleware defined in each layer. The execution order is always: application, router, and then route.
Auto-generated Swagger Documentation:
- Automatically generates Swagger documentation for each registered route, making it easier to maintain and share API documentation with others. You can view, modify, and extend the autogenerated schema.
- Added route tagging, allowing you to categorize routes and easily manage or filter them based on assigned tags. This is used when autogenerating the Swagger documentation to group together similar endpoints.
Oxygen comes with a built-in cron scheduling system that allows you to call endpoints and functions automatically when the cron expression matches the current time.
When a job is scheduled, a new task is created and runs in the background. Each task uses its given cron expression and the current time to determine how long it needs to sleep before it can execute.
The cron parser in Oxygen is based on the same specifications as the one used in Spring. You can find more information about this on the Spring Cron Expressions page.
Cron Expression Syntax
The following is a breakdown of what each parameter in our cron expression represents. While our specification closely resembles the one defined by Spring, it's not an exact 1-to-1 match.
The string has six single space-separated time and date fields:
┌───────────── second (0-59) │ ┌───────────── minute (0 - 59) │ │ ┌───────────── hour (0 - 23) │ │ │ ┌───────────── day of the month (1 - 31) │ │ │ │ ┌───────────── month (1 - 12) (or JAN-DEC) │ │ │ │ │ ┌───────────── day of the week (1 - 7) │ │ │ │ │ │ (Monday is 1, Tue is 2... and Sunday is 7) │ │ │ │ │ │ * * * * * *
Partial expressions are also supported, which means that subsequent expressions can be left out (they are defaulted to '*').
# In this example we see only the `seconds` part of the expression is defined. # This means that all following expressions are automatically defaulted to '*' expressions @cron "*/2" function() println("runs every 2 seconds") end
router() function has a keyword argument called cron, which accepts a cron expression that determines when an endpoint is called. Just like the other keyword arguments, it can be reused by endpoints that share routers or be overridden by inherited endpoints.
# execute at 8, 9 and 10 o'clock of every day. @get router("/cron-example", cron="0 0 8-10 * * *") function(req) println("here") end # execute this endpoint every 5 seconds (whenever current_seconds % 5 == 0) every5 = router("/cron", cron="*/5") # this endpoint inherits the cron expression @get every5("/first") function(req) println("first") end # Now this endpoint executes every 2 seconds ( whenever current_seconds % 2 == 0 ) instead of every 5 @get every5("/second", cron="*/2") function(req) println("second") end
In addition to scheduling endpoints, you can also use the new
@cron macro to schedule standalone functions. This is useful if you want to run code at specific times without making it visible or callable in the API.
@cron "*/2" function() println("runs every 2 seconds") end @cron "0 0/30 8-10 * * *" function() println("runs at 8:00, 8:30, 9:00, 9:30, 10:00 and 10:30 every day") end
Starting & Stopping Cron Jobs
When you run
serveparallel(), all registered cron jobs are automatically started. If the server is stopped or killed, all running jobs will also be terminated. You can stop the server and all repeat tasks and cron jobs by calling the
terminate() function or manually killing the server with
In addition, Oxygen provides utility functions to manually start and stop cron jobs:
stopcronjobs(). These functions can be used outside of a web server as well.
As we wrap up, I want to extend a sincere thank you to each and every one of you for your incredible support, insightful feedback, and active involvement with the project. Your input has played a crucial role in the growth and development of the package, and I look forward to our ongoing collaboration as we team up to make Oxygen.jl even better!
Top comments (5)
Hi Adrian, what kind of async support are you looking for? All scheduled cron functions are executed asynchronously and I believe the underlying http.jl server is asynchronous by default (when it comes to handling requests)
No worries! Feel free to ask any questions you might have in the discussions page of the github or inside our small discord server.
Given the nature of your work, you might need to handle workloads that take a considerable amount of time to complete. In most julia web frameworks this kind of behavior would cause the api to stall completely. Oxygen has built in support for multithreading, so heavy workloads can be handled in background threads which frees up the main thread to continue handling requests.
Here's a post describing how people have used this library to solve that problem: handling long running calculations