You can apply certain approaches when implementing your plug-in, for example, cache objects, bring objects in background, clone objects, and so on. By following such approaches, you can improve the performance of your plug-ins, avoid concurrency problems, and improve the responsiveness of the Orchestrator client.
Your plug-in can interact with a remote service, and this interaction is provided by local objects that represent remote objects on the service side. To achieve good performance of the plug-in as well as good responsiveness of the Orchestrator UI, you can cache the local objects instead of getting them every time from the remote service. You can consider the scope of the cache, for example, one cache for all the plug-in clients, one cache per user of the plug-in, and one cache per user of the third-party service. When implemented, your caching mechanism is integrated with the plug-in interface for finding and invalidating objects.
Bring Objects in Background
If you have to show large lists of objects in the plug-in inventory and do not have a fast way to retrieve those objects, you can bring objects in background. You can bring object in background, for example, by having objects with two states,
loaded. Assume that the
fake objects are very easy to create and provide the minimal information that you have to show in the inventory, such as name and ID. Then it would be possible to always return
fake objects, and when all the information (the real object) is really needed, the using entity or the plug-in can invoke a method
load automatically to get the real object. You can even configure the process of loading objects to start automatically after the fake objects are returned, to anticipate the actions of the using entity.
Clone Objects to Avoid Concurrency Problems
If you use a cache for your plug-in, you have to clone objects. Use of a cache that always returns the same instance of an object to every entity that requests it can have unwanted effects. For example, entity A requests object O, and the entity views the object in the inventory with all its attributes. At the same time, entity B requests object O as well, and entity A runs a workflow that starts changing the attributes of object O. At the end of its run, the workflow invokes the object's update method to update the object on the server side. If entity A and entity B get the same instance of object O, entity A views in the inventory all the changes that entity B performs, even before the changes are committed on the server side. If the run goes fine, it should not be a problem, but if the run fails, the attributes of object O for entity A are not reverted. In such a case, if the cache (the find operations of the plug-in) returns a clone of the object instead of the same instance all the time, each using entity views and modifies its own copy, avoiding concurrency issues, at least within Orchestrator.
Notify Changes to Others
Problems might occur when you use a cache and clone objects simultaneously. The biggest one is that the object that is using entity views might not be the latest version that is available for the object. For example, if an entity displays the inventory, the objects are loaded once, but at the same time, if another entity is changing some of the objects, the first entity does not view the changes. To avoid this problem, you can use the PluginWatcher and IPluginPublisher methods from the Orchestrator plug-in API to notify that something has changed to allow other instances of Orchestrator clients to see the changes. This also applies to a unique instance of the Orchestrator client when changes from one object from the inventory affect other objects of the inventory, and they need to be notified too. The operations that are prone to use notifications are adding, updating, and deleting objects when these objects, or some properties of these objects, are shown in the inventory.
Enable Finding Any Object at Any Time
You must implement the find method of the IPluginFactory interface to find objects just by type and ID. The find method can be invoked directly after restarting Orchestrator and resuming a workflow.
Simulate a Query Service if You Do Not Have One
The Orchestrator client can require querying for some objects in specific cases or showing them not as a tree but as a list or a table, for example. This means that your plug-in must be able to query for some set of objects at any moment. If the third-party technology offers a query service, you need to adapt and use this service. Otherwise, you should be able to simulate a query service, despite of the higher complexity or the lower performance of the solution.
Find Methods Should Not Return Runtime Exceptions
The methods from the IPluginFactory interface that implement the searches inside the plug-in should not throw controlled or uncontrolled runtime exceptions. This might be the cause of strange validation error failures when a workflow is running. For example, between two nodes of a workflow, the find method is invoked if an output from the first node is an input of the second node. At that moment, if the object is not found because of any runtime exception, you might get no more information than a validation error in the Orchestrator client. After that, it depends on how the plug-in logs the exceptions in to get more or less information inside the log files.