Run Manager Strategies
The Run Manager gives you control over run creation, depending on run state. You can select run creation strategies (rules) for which runs end users of your project work with when they log in to your project.
There are several strategies included in Epicenter.js:
- reuse-per-session
- reuse-across-sessions
- reuse-by-tracking-key
- reuse-last-initialized
- multiplayer-strategy
- use-specific-run-strategy
- none-strategy
You can also create your own strategy and see more details on working with Run Strategies.
reuse-per-session
The reuse-per-session
strategy creates a new run when the current one is not in the browser cookie.
Using this strategy means that when end users navigate between pages in your project, or refresh their browsers, they will still be working with the same run. However, if end users log out and return to the project at a later date, a new run is created.
This strategy is useful if your project is structured such that immediately after a run is created, the model is executed completely (for example, a Vensim model that is stepped to the end as soon as it is created). In contrast, if end users play with your project for an extended period of time, executing the model step by step, the reuse-across-sessions
strategy is probably a better choice (it allows end users to pick up where they left off, rather than starting from scratch each browser session).
Specifically, the strategy is:
- Check the
sessionKey
cookie.- This cookie is set by the Run Manager and configurable through its options.
- If the cookie exists, use the run id stored there.
- If the cookie does not exist, create a new run for this end user.
reuse-across-sessions
The reuse-across-sessions
strategy returns the latest (most recent) run for this user, whether it is in memory or not. If there are no runs for this user, it creates a new one.
This strategy is useful if end users are using your project for an extended period of time, possibly over several sessions. This is most common in cases where a user of your project executes the model step by step (as opposed to a project where the model is executed completely, for example, a Vensim model that is immediately stepped to the end).
Specifically, the strategy is:
- Check if there are any runs for this end user.
- If there are no runs (either in memory or in the database), create a new one.
- If there are runs, take the latest (most recent) one.
Strategy Options
Required? | Name | Type | Description |
---|---|---|---|
options | object |
strategy options | |
options.filter | object |
] Additional filters to retreive a run (e.g { saved: true }) etc |
reuse-by-tracking-key
The reuse-by-tracking-key
strategy creates or returns the most recent run matching a given tracking key. You can optionally also provide a "Run limit", and it'll prevent new runs from being created with this strategy once that limit has been reached.
This strategy is used by the Settings Manager to apply class settings for turn-by-turn simulations, but can also be used stand-alone.
Strategy Options
Required? | Name | Type | Description |
---|---|---|---|
Yes | settings | `object / function(): object | function(): Promise. |
Yes | settings.trackingKey | string |
Key to track runs with |
settings.runLimit | string |
Attempts to create new runs once limit is reach will return a RUN_LIMIT_REACHED error |
|
onCreate | function(RunService, object): any |
Callback will be called each time a new run is created |
reuse-last-initialized
The reuse-last-initialized
strategy looks for the most recent run that matches particular criteria; if it cannot find one, it creates a new run and immediately executes a set of "initialization" operations.
This strategy is useful if you have a time-based model and always want the run you're operating on to start at a particular step. For example:
const rm = new F.manager.RunManager({
strategy: 'reuse-last-initialized',
strategyOptions: {
initOperation: [{ step: 10 }]
}
});
This strategy is also useful if you have a custom initialization function in your model, and want to make sure it's always executed for new runs.
Specifically, the strategy is:
- Look for the most recent run that matches the (optional)
flag
criteria - If there are no runs that match the
flag
criteria, create a new run. Immediately "initialize" this new run by:- Calling the model operation(s) specified in the
initOperation
array. - Optionally, setting a
flag
in the run.
- Calling the model operation(s) specified in the
Strategy Options
Required? | Name | Type | Description |
---|---|---|---|
options.initOperation | Array.<object> |
Operations to execute in the model for initialization to be considered complete. Can be in any of the formats Run Service's serial() supports. |
|
options.flag | object |
Flag to set in run after initialization operations are run. You typically would not override this unless you needed to set additional properties as well. | |
options.scope | object |
||
options.scope.scopeByUser | boolean |
If true, only returns the last run for the user in session. Defaults to true. | |
options.scope.scopeByGroup | boolean |
If true, only returns the last run for the group in session. Defaults to true. |
multiplayer-strategy
The multiplayer
strategy is for use with multiplayer worlds. It checks the current world for this end user, and always returns the current run for that world. This is equivalent to calling getCurrentWorldForUser()
and then getCurrentRunId()
from the World API Adapater. If you use the World Manager, you are automatically using this strategy.
Using this strategy means that end users in projects with multiplayer worlds always see the most current world and run. This ensures that they are in sync with the other end users sharing their world and run. In turn, this allows for competitive or collaborative multiplayer projects.
use-specific-run-strategy
Use this strategy you already have a runid you want to use with the Run Manager (Usually used for impersonating a run)
Example:
var runOptions = window.location.search.indexOf('impersonate') === -1 ? 'reuse-across-sessions': {
strategy: 'use-specific-run',
strategyOptions: {
runId: 'runidToImpersonate' //usually passed on in the url
}
}
var rs = new F.Manager.Run(runOptions);
Strategy Options
Required? | Name | Type | Description |
---|---|---|---|
options.runId | string |
Id of Run to use |
none-strategy
The none
strategy never returns a run or tries to create a new run. It simply returns the contents of the current Run Service instance.
This strategy is useful if you want to manually decide how to create your own runs and don't want any automatic assistance.
Create your Own
You can create your own strategy by passing in a function as the strategy
parameter to the F.manager.RunManager()
instantiation call. Strategy functions must return objects of the form:
{
getRun: function() {},
reset: function() {}
}
Some strategies have options you can specify through strategyOptions
in the Run Manager. If you create your own strategy, this options object is passed in to your strategy function constructor.
For example:
// example create-your-own strategy provides a new run every minute
var ConditionalStrategy = F.manager.RunManager.strategies.byName('conditional-creation');
var myNewStrategy = new ConditionalStrategy(function (run, headers, usersession, runsession) {
var created = (new Date(run.created)).valueOf();
var timeAgo = Date.now() - created;
var runLifetime = 1;
var minsAgo = timeAgo / (1000 * 60);
return minsAgo > runLifetime;
});
var rm = new F.manager.RunManager({
strategy: myNewStrategy,
run: { ... }
});
Working with Run Strategies
You can access a list of available strategies using F.manager.RunManager.strategies.list
. You can also ask for a particular strategy by name.
If you decide to create your own run strategy, you can register your strategy. Registering your strategy means that:
- You can pass the strategy by name to a Run Manager (as opposed to passing the strategy function):
new F.manager.RunManager({ strategy: 'mynewname'})
. - You can pass configuration options to your strategy.
- You can specify whether or not your strategy requires authorization (a valid user session) to work.
Constructor options
Required? | Name | Type | Description |
---|---|---|---|
Yes | strategyName | String |
Name of strategy to get. |
Methods
byName(strategyName)
Gets strategy by name.
Parameters
Required? | Name | Type | Description |
---|---|---|---|
Yes | strategyName | String |
Name of strategy to get. |
Returns
Function
- Strategy function.
Example
var reuseStrat = F.manager.RunManager.strategies.byName('reuse-across-sessions');
// shows strategy function
console.log('reuseStrat = ', reuseStrat);
// create a new run manager using this strategy
var rm = new F.manager.RunManager({strategy: reuseStrat, run: { model: 'model.vmf'} });
register(name, strategy, options)
Adds a new strategy.
Parameters
Required? | Name | Type | Description |
---|---|---|---|
Yes | name | String |
Name for strategy. This string can then be passed to a Run Manager as new F.manager.RunManager({ strategy: 'mynewname'}) . |
Yes | strategy | Function |
The strategy constructor. Will be called with new on Run Manager initialization. |
Yes | options | Object |
Options for strategy. |
Yes | options.requiresAuth | Boolean |
Specify if the strategy requires a valid user session to work. |
Example
// this "favorite run" strategy always returns the same run, no matter what
// (not a useful strategy, except as an example)
F.manager.RunManager.strategies.register('favRun', function() {
return {
getRun: function() { return '0000015a4cd1700209cd0a7d207f44bac289'; },
reset: function() { return '0000015a4cd1700209cd0a7d207f44bac289'; }
}}, { requiresAuth: true });
var rm = new F.manager.RunManager({strategy: 'favRun', run: { model: 'model.vmf'} });