Child Scripts
Although child scripts behave similarly to the main script, there are some key differences. First of all, child scripts are optional, whereas the main script is mandatory. Additionally, there are some differences in the signature of a child script class, which are outlined below.
Example Use Cases
Some use cases where a child script can be helpful: * When you want to monitor price drops and, once the price is below a certain amount, purchase the product with multiple accounts simultaneously. The price drop monitoring can be part of the main script, while the purchasing process can be handled by the child script. This setup results in a single task monitoring the price drop and multiple concurrent tasks performing the checkout. * When you first need to retrieve available products and, after retrieving the list, monitor each product for changes in stock. Retrieving the list of available products can be part of the main script, while a child script can be created to monitor individual products.
Creating a Child Script
An example implementation of a child script looks like this:
@ChildScript(
id = "CHILD_SCRIPT_ID",
name = "My child script",
)
class MyChildScript(private val parameters: ScriptParameters) : Script<MyChildConfiguration> {
override suspend fun onStart(
configuration: MyChildConfiguration,
provider: ComponentProvider,
): Boolean {
// TODO
return true
}
override suspend fun execute(
configuration: MyChildConfiguration,
provider: ComponentProvider,
statusUpdate: suspend (message: String) -> Unit,
): ExecutionResult {
// TODO
return ExecutionResult.Success("Success")
}
override suspend fun onFinish(
configuration: MyChildConfiguration,
provider: ComponentProvider,
) {
// TODO
}
}
The MyChildConfiguration interface is defined the same way as usual, as outlined on the script configuration page.
@ChildScript(
All child scripts require this annotation to be detected as a child script.
id = "CHILD_SCRIPT_ID",
This is the unique ID for your child script. When creating multiple child scripts, make sure this ID is unique within your package. You can create this ID yourself, but it must remain consistent across releases of your script to ensure that the state is correctly stored and restored by Cereal.
name = "My child script",
A human-readable name used as the display name for your script. It should, therefore, describe the purpose of the child script.
class MyChildScript(private val parameters: ScriptParameters) : Script<MyChildConfiguration> {
The script class optionally accepts ScriptParameters, which are provided when the child script is started by one of your other scripts. Since the child script implements the same Script interface as your main script, the methods you need to implement are identical.
Starting a Child Script
You can start a child script from within any other script using the ScriptLauncherComponent available in the ComponentProvider. For more information on component providers, see this page. The ScriptLauncherComponent contains a start method that accepts the child script class type and, optionally, any parameters you'd like to pass to the child script. A handle is returned, allowing you to poll the execution status of the child scripts that are started.
val scriptLauncher = provider.scriptLauncher()
val handle = scriptLauncher.start(MyChildScript::class.java)
The start method throws StartScriptException if the child script cannot be started.
Passing Data with ScriptParameters
ScriptParameters is a typed key-value bag for sending data from a parent script to a child script.
val params = ScriptParameters()
params.putString("productId", "ABC-123")
params.putInteger("quantity", 2)
params.putLong("startTime", System.currentTimeMillis())
params.putDouble("maxPrice", 49.99)
params.putFloat("discount", 0.1f)
val handle = scriptLauncher.start(MyChildScript::class.java, params)
Inside the child script, read the parameters from the constructor argument:
@ChildScript(id = "CHILD_SCRIPT_ID", name = "My child script")
class MyChildScript(private val parameters: ScriptParameters) : Script<MyChildConfiguration> {
override suspend fun onStart(
configuration: MyChildConfiguration,
provider: ComponentProvider,
): Boolean {
val productId = parameters.getString("productId") // returns null if key not set
val quantity = parameters.getInteger("quantity") ?: 1
return true
}
// ...
}
Supported ScriptParameters types
| Put method | Get method | Type |
|---|---|---|
putString |
getString |
String |
putInteger |
getInteger |
Int |
putLong |
getLong |
Long |
putDouble |
getDouble |
Double |
putFloat |
getFloat |
Float |
putByte |
getByte |
Byte |
putShort |
getShort |
Short |
putInstant |
getInstant |
Instant |
All getters return null if the key has not been set. ScriptParameters is not thread-safe — confine access to a single coroutine.