This Best Practices document should offer some guidelines and tips & tricks on how to work with Timers and Schedulers in ThingWorx. After exploring the configuration and creation of Timers and Schedulers via the UI or JavaScript Services, this document will also highlight some of the most common performance issues and troubleshooting techniques.
- Timers and Schedulers can be used to run jobs or fire events on a regular basis. Both are implemented as Thing Templates in ThingWorx. New Timer and Scheduler Things can be created based on these Templates to introduce time based actions.
- Timers can be used to fire events in a certain interval, defined in the Timer's Update Rate (default is 60000 milliseconds = 1 minute).
- Schedulers can be used to run jobs based on a cron pattern (such as once a day or once an hour). Schedulers will also allow for a more detailed time based setup, e.g. based on seconds, hours, days of week or days months etc.
- Events fired by both Timers and Schedulers can be subscribed to with Subscriptions which can be utilized to execute custom service scripts, e.g. to generate "fake" or random demo data to update Remote Things in a test environment. In general subscriptions and scripts can be used to e.g. run regular maintenance tasks or periodically required functions (e.g. for data aggregation)
For more information about setting up Timers and Schedulers it's recommended to also have a look at the following content:
Example
The following example will illustrate on how to create a Timer Thing updating a Remote Thing using random values. To avoid any conflicts with permissions and visibility, use the Administrator user to create Things.
Remote Thing
- Create a new Thing based on the Remote Thing Template, called myRemoteThing.
- Add two properties, numberA and numberB - both Integers and marked as persistent.
- Save myRemoteThing.
Timer Thing
- Create a new Thing based on the Timer Template, called myTimerThing.
- In the Configuration, change the
- Update Rate to 5000, to fire the Event every 5 seconds.
- User Context to Administrator. This will run the related services with the Administrator's user visibility and permissions.
- Save myTimerThing.
Subscriptions
- To update the myRemoteThing properties when the Timer Event fires, there are two options:
- Configure a Subscription on myRemoteThing and listen to Timer Events on the myTimerThing.
- Configure a Subscription on myTimerThing and listen to Timer Events on itself as a source.
- In this example, let's go with the first option and Edit myRemoteThing.
- Create a new Subscription pointing to myTimerThing as a Source.
- Select the Timer Event
Note that if no source is selected, the Timer Event is not availabe, as myRemoteThing is based on the Remote Thing Template and not the Timer Template
- Enable the Subscription.
- In the Script area use the following code to assign two random numbers to the Thing's custom properties:
me.numberA = Math.floor(Math.random() * 100);
me.numberB = Math.floor(Math.random() * 100);
Validation
- The Subscription will be enabled and active on saving it.
- Switch to the myRemoteThing Properties
- Refreshing the Values will show updates with random numbers between 0 and 99 every 5 seconds (Timer Update Rate).
Performance considerations
- Timers and Schedulers are handled via the Event Processing Subsystem. Metrics that impact current performance can be seen in Monitoring > Subsystems > Event Processing
- Implementing Timers and Schedulers on a Thing Template level might flood the system with services executions originating from Subscriptions to Timer / Scheduler triggered Events.
- Subscribing to another Thing's Events will be handled via the Event Processing Subsystem.
- Subscribing to an Event on the same Thing will not be handled via the Event Processing Subsystem, but rather execute on the already open in memory Thing.
- If Timers and Schedulers are not necessarily needed, the Services can be triggered e.g. via Data Change Events, UI Interactions etc.
- Recursion can be a hidden performance contributer where a Subscription to a certain Event executes a service, triggering another Event with recursive dependencies. Ensure there are no circular dependencies and service calls across Entities.
- If possible, reads for each and every action from disk should be avoided. Performance can be increased by storing relevant information in memory and using Streams or Datatables or for persistence.
- If possible, call other Services from within the Subscription instead of handling all code within the Subscription itself.
- For full details, see also Timers and Schedulers - Best Practice
How to identify and troubleshoot technical issues
- Check the Event Processing Subsystem for any spikes in queued Events (tasks submitted) while the total number of tasks completed is not or only slowly increasing. For a historical overview, search the ApplicationLog for "Thingworx System Metrics" to get system metrics since the server has been (re-) started.
- In the ApplicationLog the message "Subsystem EventProcessingSubsystem is started" indicates that the Subsystem is indeed started and available.
- Use custom loggers in Services to get more context around errors and execution in the ScriptLog
- Custom Loggers can be used to identify if Events have fired and Subscriptions are actually triggered
- Example: logger.debug("myThing: executing subscribed service")
- For issues with Service execution, see also CS268218
- Infinite loops in Services could render the server unresponsive and might flood the system with various Events
- To change the timing for a Timer, restarting the Thing is not enough. The Timer must be disabled and enabled at the desired start time. Schedulers will allow for a much more flexible timing and setting / changing execution times in advance.
- For further analysis it's recommended to generate Thread Dumps to get more information about the current state of Threads in the JVM. The ThingWorx Support Tools Extension can help in generating those. See also CS245547 for more information and usage.