Carbon Aware Jobs
Use Carbon Aware Job Processing to optimize the carbon footprint when scheduling (recurring) jobs.
Configuration note: In order to enable carbon aware capabilities for your jobs, please correctly setup the Carbon Aware Job Processing Configuration.
Adding a margin to your regular (recurring) schedule allows your jobs to be executed at the optimal time: when the CO2 footprint for your local region is the lowest. Instead of immediately scheduling a job, it will be created in a new pending mode and scheduled as soon as JobRunr receives carbon intensity data to optimize the carbon footprint of your job.
The following schematic summarizes how carbon aware job processing works:
As visible in the schematic, for carbon aware job processing, these concepts are important:
- The preferred time—your usual schedule when the job should be processed. If something goes wrong (see important remarks), the job will still be processed using this as a fallback.
- The carbon aware margin [From, To]—instead of always scheduling the job at the preferred time, with carbon aware, the job can be processed anywhere within this margin depending on the data of the energy provider. The interval limit can be seen as a deadline: if it is passed, the job will still be executed at that time.
- The carbon optimal time—this is a moment in-between the above margin JobRunr selects as the time when the CO2 footprint is the lowest. This is the new scheduled at time. In this example, the job runs later than the initial preferred time, but still well within the deadline.
As usual, you can track the progress of your job in the dashboard:
Both delayed jobs and recurring jobs can be made carbon aware. The following sections explain this in detail:
Carbon Aware Scheduled Jobs
For general documentation on scheduled jobs, see Scheduled Jobs.
As with scheduling regular jobs, you can use either the jobScheduler.schedule()
method and pass in the desired delay & margin:
BackgroundJob.scheduleCarbonAware(CarbonAwarePeriod.between(now, now.plus(5, HOURS)),
() -> myService.sendNewlyRegisteredEmail());
Note the used method here is scheduleCarbonAware()
instead of your regular schedule()
!
Or you can use the JobBuilder
to achieve the same result:
BackgroundJob.create(aJob()
.withName("Send welcome email to newly registered users")
.scheduleCarbonAware(CarbonAwarePeriod.between(now, now.plus(5, HOURS)))
.withDetails(() -> myService.sendNewlyRegisteredEmail()));
Note that the used builder method here is scheduleCarbonAware()
instead of your regular scheduleIn()
!
The following subsection details the different possibilities for creating a carbon-sepcific schedule.
Creating Carbon Aware Periods
The CarbonAwarePeriod
class houses several utility methods to quickly create a period and add some carbon aware slack. There are two main possibilities:
before(time)
is a simple way to express you want to get a job done before certain time in the future. This is an alias forbetween(now(), time)
.between(startTime, endTime)
is a way to express you want to kick a job into gears between a certain period in the future. It can accept the following class instances
Both methods accept the following class instances: Instant
, LocalDate
, LocalDateTime
(using the system default zone ID), and ZonedDateTime
.
Carbon Aware Recurring Jobs
For general documentation on recurring jobs, see Recurring Jobs.
The following subsection details the different possibilities for creating a carbon-aware recurring job.
Creating Carbon Aware Schedule Expressions using a utility class
The CarbonAware
class houses several utility methods to quickly create a carbon aware schedule expression string:
dailyBetween(fromHour, untilHour)
: allows relaxing of a daily schedule as long as it stays withinfromHour
anduntilHour
hours. Both parameters need to be in 24-hour format and should be within the same day (they cannot cross the 12-hour boundary: e.g. between 20H and 6H the next day); for that employusing()
instead.dailyBefore(untilHour)
: alias ofdailyBetween(0, untilHour)
using(cronExpression, marginBefore, marginAfter)
: allows relaxing of a schedule expression string by[marginBefore, marginAfter]
wheremarginBefore
andmarginAfter
areDuration
instances (e.g.using("0 16 * * *", Duration.ofHours(1), ofHours(4))
will schedule between 15 p.m. and 20 p.m.).using(fixedDelay, marginBefore, marginAfter)
: allows relaxing of a recurring job with a fixed delay between runs by[marginBefore, marginAfter]
where all parameters areDuration
s.
The
using
method accepts any valid scheduleExpression string, meaning that you can use the same methods for custom schedules available in JobRunr Pro!
Creating Carbon Aware Schedule Expressions manually
Of course, you always have the option to add the carbon aware margin to the CRON expression string by hand. We have extended the schedule expression notation (for cron or interval recurring jobs) to accept carbon aware margins. For example, you can either rely on using()
as shown in the above section, or just create the string yourself:
// Both are exactly the same
jobScheduler.scheduleRecurrently("rj-id", CarbonAware.using("0 16 * * *", Duration.ofHours(1), ofHours(4)), x->doWork())
jobScheduler.scheduleRecurrently("rj-id", "0 16 * * * [PT1H/PT4H]", x->doWork())
The notation is scheduleExpression [marginBefore/marginAfter]
(e.g., 0 8 * * * [PT0S/PT5H]
for a recurring running daily between 8 a.m. and 1 p.m.) where a space separates the usual schedule expression from the carbon aware margin, the square brackets
[]
identify the interval, and the slash /
separates the margin from/margin to.
This notation allows use to specify margins when using the @Recurring
annotation:
@Recurring(id="doing-some-thing-recurrently-carbon-aware", cron="0 8 * * * [PT0S/PT5H]")
@Job(name="A job doing some work")
public void doWork() {
// doing some work
}
In the Dashboard, in the Recurring Jobs tab, you can see whether a Cron is a carbon-specific Cron by hovering over the electrified leaf icon:
⚠️ Important Remarks
When making use of carbon aware schedules, there are a few important things to keep in mind:
- If the margin is too small, the job will be scheduled right away instead. This depends from energy data provider to data provider and from area code to area code. Most providers return carbon intensity data with hourly margins, but the EU is migrating to each 15 minutes. The configured margin should be three times as big as the margins returned by the data provider (e.g. if hourly, at least three hours). It does not make sense to schedule a job carbon aware between now and one hour if JobRunr does not receive carbon info between that margin.
- If the Carbon Intensity API is down or cannot be reached (e.g., because of a firewall), jobs will be scheduled at their preferred time.
- If the Carbon Intensity API has no forecast for a particular period, the job will be scheduled at their preferred time.
- If the deadline has passed (e.g.
between(now, now.plus(3, HOURS)
and it’s past the third hour), the job will be scheduled immediately. - If Carbon Aware Job Processing is disabled, remaining carbon aware jobs in
AWAITING
will be processed and scheduled at their preferred time.
For each of the above cases, a specific reason will be recorded that can be consulted in the dashboard when opening the job details.