Create an optimization extension
Overview
Optimization extensions enable you to create custom scheduling logic to meet the specific needs of your organization, enhancing scheduling workflows. With these extensions, you can build, deploy, and apply your own rules more efficiently through Skedulo’s platform, reducing both time and effort. They are built using Skedulo’s connected functions.
These extensions are integrated into Skedulo’s optimization recipes. Once created and deployed, your scheduling teams can easily use them within the web app to optimize scheduling processes.
This guide walks you through the steps to create, write, and test your custom rules and constraints using the Skedulo CLI.
For a working example, see optimization extension example repo. This example shows how to ensure that all the jobs being optimized are scheduled to one singular resource.
Prerequisites
You’ve installed the Skedulo CLI. See Install the Skedulo CLI.
Create an optimization extension
Do the following steps to create an optimization extension using the Skedulo CLI.
-
After logging into your team, create a new connected function to host the extension by running the following command in your terminal or command prompt:
sked function generate -n {function_name} -o
For more information, see sked function generate.
The project will be created with the function name you specified.
-
Open the project created in your code editor. Then add the
optimization-manager-client
package to your project.This package contains utilities that help to set up the extension.
yarn add @skedulo/optimization-manager-client yarn install
-
Navigate to the
/src/routes.ts
file in your connected function. Update the returned routes to contain the endpoints necessary for an optimization extension. This is done using a helper method from the utility package.function getRoutes(): FunctionRoute[] { return createOptimizationRoutes(transformSchedule); }
The
transformSchedule
parameter must be a function that does the work of the extension. For example:const transformSchedule = async (transformerInput: TransformerInput): Promise<TransformerOutput> => { const newFeatureModel = \\Transform transformerInput.featureModel to add required features return { productData: transformerInput.productData, featureModel: newFeatureModel }; }
See this section for more information on how to write an extension.
For a working example, see this optimization extension example repo.
-
Once you have created your extension, you can deploy it to your tenant (team) using the CLI by executing the following command in your project’s root directory:
sked artifacts function upsert -f {function_name}/state.json
Once it is deployed successfully, the scheduling team should then be able to add the custom extension to an optimization recipe, which will be applied during the optimization process. You can apply one or many to each recipe as needed.
- Open an optimization recipe. Scroll down to the bottom of the page, and select one or many recipe extensions that you want to apply.
Refer to optimization recipe for more details on how to use an optimization recipe.
Write an extension
The important part of the extension is the function that transforms the data model. This function has the type signature:
TransformerInput => Promise<TransformerOutput>
TransformerInput
The function’s input has the following fields available:
interface TransformerInput {
productData: APIProductData;
featureModel: CorePVRPFeatureModelShape;
plan: Plan;
configuration: ApiConfig;
}
Here is a summary of what each data type contains and how it is used:
Data type | Description |
---|---|
productData |
Contain all the data collected for an optimization run, including all the work and resources. It’s not directly used by the optimization engine, but it is used when creating the results to be saved after a run. You don’t need to modify the product data if you are using an extension to add custom constraints to a run. However, if the extension is used to exclude specific resources or work items, you may need to update the product data to ensure those exclusions are reflected in the final results. |
featureModel |
This is the data used by the optimization engine to perform a run. It includes all work, resources, and constraints applied during the run, which can be modified in an extension to produce different results. Once you have imported the optimization-manager-client utility package, you can inspect the types to see what aspects can be changed for an optimization run. |
plan |
Contain the original data models before any changes are made. Multiple extensions can be added to an optimization run, and the productData and featureModel may already be modified by the time an extension runs. The plan field ensures access to the initial data models in case they’re needed in an extension. |
configuration |
Contain the base URL of the current environment and a token for making requests. This allows you to make requests to other Skedulo services within an extension. For example, you can use this to retrieve custom objects from GraphQL. |
TransformerOutput
This contains the results of all the transformations you have made to the productData
and featureModel
. The other fields from the TransformerInput
do not need to be passed in here.
interface TransformerOutput {
productData: APIProductData;
featureModel: CorePVRPFeatureModelShape;
}
Test an extension
Extensions are integrated into the optimization flow. This can make it difficult to test and debug them end-to-end quickly during development. Therefore, the createOptimizationRoutes(transformSchedule)
in the optimization-manager-client
package offers tools that help expose and test the feature model changes.
To test feature model changes directly, the /test-optimization-transformer
route takes an optimization plan
as its input, runs synchronously through the steps to get to the transformer, and returns the output from the transformer. This allows you to verify the changes to the feature model without having to use the extension in a recipe.
You can run your optimastion extension function locally by with the Skedulo CLI by running:
sked function dev ./{function_name} -p 60000
Once you’ve tested and updated the feature model, you can send the feature model to the /solve
endpoint to check if the feature model is valid and behaves as expected.
Tip
To reduce the run time, we suggest you setignoreTravelTime
to true
while testing.
Test input example
Function in development on port 60000 with Skeduo CLI
POST http://127.0.0.1:60000/test-optimization-transformer
{
"resourceIds": [
"0005cdec-5617-4a9b-bf60-4a5d372e9347"
],
"jobIds": [
"0014cd70-a7ed-4f2a-bcac-1dc2ff34afc5"
],
"regionId": "0003c1f5-a508-4bb3-ba82-b4261f71d067",
"scheduleWindow": {
"start": "2024-11-04T08:00:00.000Z",
"end": "2024-11-09T08:00:00.000Z"
},
"timezone": "Europe/Brussels",
"options": {
"respectSchedule": false,
"full": false,
"ignoreTravelTime": false,
"ignoreTravelTimeFirstJob": true,
"ignoreTravelTimeLastJob": true,
"minimizeResources": false,
"maxTravelTimeBetweenLocations": null,
"respectAllocationTimes": false,
"respectAllocationTimesOverTimeConstraints": false,
"balanceAbsoluteWorkload": false,
"randomizeResources": false,
"objectiveWeights": {
"preferredResources": 10,
"minimizeDisruption": 10,
"balanceAbsoluteWorkload": 60,
"travelTime": 10,
"minimizeResources": 0,
"softSkills": 10,
"jobsPriority": 10
},
"enablePartiallyAllocatedGroups": true,
"waitingSynchronizationMode": "groupsOnly"
}
}
Feedback
Was this page helpful?