Optimized scheduling using the Skedulo API
You can use optimization to find a valid solution to scheduling multiple jobs across your resources during a scheduling window.
The optimization feature allows you to specify the scheduling window, the jobs you want to optimize, and optimization options or constraints.
The /optimization/schedule
REST API endpoint requires the following fields in the request body:
Field | Type | Description |
---|---|---|
jobIds |
Array of string | An array of job IDs for which you want to schedule and allocate resources. |
resourceIds |
Array of string | An array of resource IDs that can be allocated and scheduled for the jobs. |
scheduleStart |
String <date-time> (TimeStamp) | Can be either ISO8601 date time string or Unix timestamp number ( in milliseconds ). Always returned in ISO8601 format. |
scheduleEnd |
String <date-time> (TimeStamp) | Can be either ISO8601 date time string or Unix timestamp number ( in milliseconds ). Always returned in ISO8601 format. |
timeZone |
String | Scheduling timezone. |
schedulingOptions |
object(SchedulingOptions ) |
Constraints that the optimization engine must consider when creating the schedule. |
Optimization schedulingOptions
are a way to configure the optimization engine to take specific business requirements into account, adding further constraints to your query.
The following schedulingOptions
are available:
Field | Description | Type | Default |
---|---|---|---|
balanceWorkload |
Equalize total allocated duration including travel time for each resource. | Boolean | false |
minimizeResources |
Attempt to allocate to the fewest number of resources in a scheduling window. | Boolean | false |
jobTimeAsTimeConstraint |
When a job has a time set, consider it to be a time constraint and never reschedule to another time slot. | Boolean | true |
preferJobTimeOverTimeConstraint |
When a job with a JobTimeConstraint also has a time set, consider the job time as the authoritative constraint and ignore the JobTimeConstraint. | Boolean | true |
respectSchedule |
For a job that is allocated and in “Pending Dispatch” status, do not move the job to a different time. | Boolean | true |
ignoreTravelTimes |
Ignore all travel times between resources and jobs. | Boolean | false |
ignoreTravelTimeFirstJob |
Ignore travel time from a resource’ home location to the first job. | Boolean | false |
ignoreTravelTimeLastJob |
Ignore travel time to the resource’ home location from the last job. | Boolean | false |
padding |
A fixed interval in seconds between consecutive jobs. | Integer | 0 |
snapUnit |
Divide the given time frame into parts described by this value and allocate all jobs to the nearest part in seconds. | Integer | 0 (>=0) |
maxTravelTimeInMinutes |
When set to a number greater than zero (0 ), do not schedule nodes with a travel time that exceeds this value in minutes. |
Integer | 0 |
Request body schemas for /optimization/schedule
The /optimize/schedule
endpoint has two different ways of specifying the resources you want to include in the request:
- The
resources
object contains the IDs of the resources you want to schedule for jobs, including their availability window. This is useful when making the request from an external system where the resource record might not be available. - The
resourceIds
property is an array of resource IDs that can be scheduled for jobs.
Example request body using the resources
object
The resources
object that contains the resource IDs and an array of start
and end
timestamps for the working hours of those resources.
Working hours override availability that is already set up for the resource, so this is a way to account for a varied or one-off changes to a resource’s normal working hours.
For example, if a resource normally only works from 9AM to 5PM during the week but has elected to be available for overtime shifts this weekend, this can be included as working hours.
The following is an example of a request for the /optimization/schedule
endpoint using the resources
object:
{
"jobIds": [
"001406d4-51fd-4da7-8960-1e71429e1974",
"0014c5a0-05eb-4d16-8381-f63d17bda9d6",
"00142eaa-a8f3-4e90-942b-3233fff67936"
],
"resources": {
"0005dfa7-c49e-481c-a25c-6daef8e3d918": [],
"0005094d-dae5-4cbb-ad7d-db78d3735e21": [{ "start": "2019-04-17T04:00:30.000Z", "end": "2019-04-17T0:20:30.000Z" }]
},
"scheduleStart": 1555475530486,
"scheduleEnd": 1555509599999,
"timeZone": "Australia/Brisbane",
"schedulingOptions": {
"respectSchedule": false,
"ignoreTravelTimes": true,
"ignoreTravelTimeFirstJob": false,
"ignoreTravelTimeLastJob": false,
"jobTimeAsTimeConstraint": true,
"preferJobTimeOverTimeConstraint": true,
"balanceWorkload": false,
"minimizeResources": false,
"snapUnit": 0,
"padding": 0
}
}
Example request body using the resourceIds
property
The resourceId
property is an array of resource IDs that can be scheduled for the jobs included in the request.
The following is an example of an /optimization/schedule
request using the resourceIds
property:
{
"jobIds": [
"001406d4-51fd-4da7-8960-1e71429e1974",
"0014c5a0-05eb-4d16-8381-f63d17bda9d6",
"00142eaa-a8f3-4e90-942b-3233fff67936"
],
"resourceIds": [
"0005dfa7-c49e-481c-a25c-6daef8e3d918"
"000577e0-2d69-4e84-a1c3-1878d64f85f0"
],
"scheduleStart": 1555475530486,
"scheduleEnd": 1555509599999,
"timeZone": "Australia/Brisbane",
"schedulingOptions": {
"respectSchedule": false,
"ignoreTravelTimes": true,
"ignoreTravelTimeFirstJob": false,
"ignoreTravelTimeLastJob": false,
"jobTimeAsTimeConstraint": true,
"preferJobTimeOverTimeConstraint": true,
"balanceWorkload": false,
"minimizeResources": false,
"snapUnit": 0,
"padding": 0
}
}
Example: Get a valid schedule using the /optimization/schedule
endpoint
Use the following procedure to make a request to the /optimization/schedule
endpoint and get a valid schedule using the ScheduleResourceIdsBody
request schema.
The example includes 10 jobs that we want to schedule on Monday. There are three resources that we are including in the query, and we would like the schedule to use minimum resources (minimizeResources
):
- Create a
ScheduleResourceIdsBody
request body including thejobIds
andresourceIds
for the jobs and resources that you want to include in your optimization query, and the scheduling window.
{
"jobIds": [
"00146e2f-c8db-4593-adc2-084abc866785","0014586b-3fa3-4f74-a5b1-a47f22a4b3a2","0014b2b8-6543-4d3a-b39f-91d9ccadb12f","001419d8-ea58-40d8-8fc9-7e5e114af0e0","00144739-bd24-462b-8f6a-ff01a3c80671","00143563-d261-4a7d-9416-2244447250c2","00140dcd-b523-4250-921b-4eb32d29d043","00148397-e956-4232-854a-ed5c6f91455e","00141ae5-a30e-44d9-a24b-a04ed98c24f9","0014e1ba-eddd-447c-ae80-62954c637820"
],
"resourceIds": [
"000521e3-b4ab-417e-8fc2-23647246b085", "0005a7e9-b1aa-44da-937f-310b921b75cc", "000520bd-63a1-47a0-9c80-9a343cb35ec6"
],
"scheduleStart": "2019-07-15T00:00:00+1000",
"scheduleEnd": "2019-07-15T23:59:59+1000",
"timeZone": "Australia/Brisbane",
"schedulingOptions": {
"respectSchedule": false,
"ignoreTravelTimes": false,
"ignoreTravelTimeFirstJob": true,
"ignoreTravelTimeLastJob": true,
"jobTimeAsTimeConstraint": true,
"preferJobTimeOverTimeConstraint": true,
"balanceWorkload": false,
"minimizeResources": true,
"snapUnit": 0,
"padding": 5
}
}
This provides the following JSON response, which is a result that assigns all 10 jobs to two of the three resources:
{
"result": {
"score": {
"hardScore": 0,
"mediumScore": 0,
"softScore": -10000
},
"timeToSolve": 2023,
"routes": [
{
"resourceId": "000520bd-63a1-47a0-9c80-9a343cb35ec6",
"resourceName": "David Kimi",
"route": [
{
"jobId": "00140dcd-b523-4250-921b-4eb32d29d043",
"jobName": "JOB-0028",
"start": "2019-07-15T03:29:00.000Z",
"duration": 50,
"travelTime": 29,
"type": "job"
},
{
"jobId": "001419d8-ea58-40d8-8fc9-7e5e114af0e0",
"jobName": "JOB-0003",
"start": "2019-07-14T22:30:00.000Z",
"duration": 10,
"travelTime": 0,
"type": "job"
},
{
"jobId": "0014586b-3fa3-4f74-a5b1-a47f22a4b3a2",
"jobName": "JOB-0009",
"start": "2019-07-14T22:45:00.000Z",
"duration": 60,
"travelTime": 0,
"type": "job"
},
{
"jobId": "00146e2f-c8db-4593-adc2-084abc866785",
"jobName": "JOB-0006",
"start": "2019-07-14T23:50:00.000Z",
"duration": 90,
"travelTime": 0,
"type": "job"
},
{
"jobId": "00148397-e956-4232-854a-ed5c6f91455e",
"jobName": "JOB-0015",
"start": "2019-07-15T01:25:00.000Z",
"duration": 90,
"travelTime": 0,
"type": "job"
},
{
"jobId": "0014b2b8-6543-4d3a-b39f-91d9ccadb12f",
"jobName": "JOB-0023",
"start": "2019-07-15T04:31:00.000Z",
"duration": 60,
"travelTime": 7,
"type": "job"
},
{
"jobId": "0014e1ba-eddd-447c-ae80-62954c637820",
"jobName": "JOB-0022",
"start": "2019-07-15T06:23:00.000Z",
"duration": 60,
"travelTime": 47,
"type": "job"
}
]
},
{
"resourceId": "000521e3-b4ab-417e-8fc2-23647246b085",
"resourceName": "Mary Brown",
"route": [
{
"jobId": "00141ae5-a30e-44d9-a24b-a04ed98c24f9",
"jobName": "JOB-0016",
"start": "2019-07-14T23:00:00.000Z",
"duration": 120,
"travelTime": 0,
"type": "job"
},
{
"jobId": "00143563-d261-4a7d-9416-2244447250c2",
"jobName": "JOB-0014",
"start": "2019-07-15T02:10:00.000Z",
"duration": 50,
"travelTime": 65,
"type": "job"
},
{
"jobId": "00144739-bd24-462b-8f6a-ff01a3c80671",
"jobName": "JOB-0008",
"start": "2019-07-15T03:05:00.000Z",
"duration": 90,
"travelTime": 0,
"type": "job"
}
]
}
],
"unscheduled": []
}
}
- You can save these results and dispatch the jobs using a GraphQL mutation:
-
The GraphQL query uses aliases to allocate multiple jobs to resources in a single query.
-
You must provide an
End
time for the job.The following example allocates and dispatches the three jobs that were assigned to Mary Brown:
mutation saveOptimizationResult { schema { _j0: updateJobs(input: { UID: "00141ae5-a30e-44d9-a24b-a04ed98c24f9" Start: "2019-07-14T23:00:00.000Z", End: "2019-07-15T01:00:00.000Z" }) _ja0: insertJobAllocations(input: { JobId: "00141ae5-a30e-44d9-a24b-a04ed98c24f9" ResourceId: "000521e3-b4ab-417e-8fc2-23647246b085" }) _j1: updateJobs(input: { UID: "00143563-d261-4a7d-9416-2244447250c2" Start: "2019-07-15T02:10:00.000Z" End: "2019-07-15T03:00:00.000Z" }) _ja1: insertJobAllocations(input: { JobId: "00143563-d261-4a7d-9416-2244447250c2" ResourceId: "000521e3-b4ab-417e-8fc2-23647246b085" }) _j2: updateJobs(input: { UID: "00144739-bd24-462b-8f6a-ff01a3c80671" Start: "2019-07-15T03:05:00.000Z" End: "2019-07-15T04:35:00.000Z" }) _ja2: insertJobAllocations(input: { JobId: "00144739-bd24-462b-8f6a-ff01a3c80671" ResourceId: "000521e3-b4ab-417e-8fc2-23647246b085" }) } }
A successful result provides the following response with IDs for each successful operation:
{ "data": { "schema": { "_j0": "00141ae5-a30e-44d9-a24b-a04ed98c24f9", "_ja0": "00186136-fdad-4a2b-82c0-ead73cc6c3a7", "_j1": "00143563-d261-4a7d-9416-2244447250c2", "_ja1": "00182053-28dd-4e6f-8f8e-69d60fda0755", "_j2": "00144739-bd24-462b-8f6a-ff01a3c80671", "_ja2": "0018a0cb-cde2-48a7-98bb-e8c10c93b915" } } }
Open the scheduling window to see that the jobs have been scheduled and allocated to Mary Brown and are
Pending Dispatch
.
-
You can dispatch the jobs by selecting them in the scheduling window and clicking
Notify
in the scheduler. Alternatively, you can dispatch the jobs using GraphQL:mutation dispatchJobs { schema { _j0: updateJobs(input: { UID: "00141ae5-a30e-44d9-a24b-a04ed98c24f9" JobStatus: "Dispatched" }) _j1: updateJobs(input: { UID: "00143563-d261-4a7d-9416-2244447250c2" JobStatus: "Dispatched" }) _j2: updateJobs(input: { UID: "00144739-bd24-462b-8f6a-ff01a3c80671" JobStatus: "Dispatched" }) } }
Or you can dispatch the jobs using the
/notify/dispatch
endpoint, which also triggers the dispatch workflow:{ "jobId": "00141ae5-a30e-44d9-a24b-a04ed98c24f9", "resourceIds": [ "000521e3-b4ab-417e-8fc2-23647246b085" ] }
Feedback
Was this page helpful?