Skip to main content
Version: 10.2.8

Exclusive access with pool

Exclusive access concept

The pool plugin was created to provide exclusive access to a record from a Data Store or a collection. This is essential to address the typical business requirement that only one user session can utilize a particular pair of credentials simultaneously.

In technical words, the plugin provides the semaphore functionality for objects in the list section. For each invocation, the plugin returns any unborrowed object from the evaluated list. Check whether the object is borrowed in a pairwise comparison based on the borrowed object equals method.

For more details, refer to Bot Task plugins | pool

ODF 2 and pool

info

The pool pattern guarantees that the method using it synchronously accesses a certain collection item. If another record of your Business Process executes the same code in parallel and tries to access this collection item, it will wait until the first record or thread finishes and hence "releases" the item.

Every ODF 2 Bot Task uses the pre-defined WebHarvestServicesModule module instantiated at the entry point for the whole framework. It is called from the generated Bot Task code where the platform service wrappers are provided as injectables.

Among other useful services, the module provides PoolObjectFactory that can be used to create and execute pool. Inject PoolObjectFactory into your Bot Task constructor to build and execute its PoolObjectRunner:

@BotTask(requireRpa = true, roboticsFleet = "processor_user")
public class PoolLoginAndPerformRpaTask implements GenericTask {

private final PoolObjectRunner poolRunner;
private final RpaRunner rpaRunner;
private final TaskOutput taskOutput;
public static final String AVAILABLE_PROCESSORS_LIST = "users.processors";

@Inject
public PoolLoginAndPerformRpaTask(PoolObjectFactory poolObjectFactory, TaskOutput taskOutput, Configuration configuration, RpaFactory rpaFactory) {
this.poolObjectFactory = poolObjectFactory;
this.poolRunner = this.poolObjectFactory.builder("pool_runner").waitTimeout(Integer.parseInt(configuration.getRequiredProperty(RobotConfigurationConstants.POOL_PLUGIN_TIMEOUT))).build();
rpaRunner = rpaFactory.builder(RpaDriver.UNIVERSAL).closeOnCompletion(true).capability(CapabilityType.PAGE_LOAD_STRATEGY, "eager").maximizeOnStartup(true).startInPrivate(false).build();
this.taskOutput = taskOutput;
}

@Override
public TaskRunnerOutput run(TaskInput taskInput) {
List<String> processorsList = Arrays.asList(configuration.getRequiredProperty(AVAILABLE_PROCESSORS_LIST).split(","));
try {
poolRunner.execute(processorsList, user -> {

/*
The platform guarantees that, within this section, no other record of the Bot Task running in parallel (BEP Worker Java threads) can work with the particular item from the pool.
*/

String username = (String) user;
SecureEntryDTO processor = svService.getEntry(username.trim());
runBot(processor);
});
} catch (PluginException e) {
getLogger().info("Pool plugin exception: " + e.getMessage());
}
return new SingleResult(Maps.of("PoolObjectFromSingletonList run", "SUCCESS"));
}

private void runBot(SecureEntryDTO user) {
this.botUser = user;
rpaRunner.execute(driver -> {

...

String userPassword = user.getValue();

...

try {
mainPage = robot.doLogin(user.getKey(), userPassword);

...

} catch (LoginFailedException e) {
addScreenShot();
throw new LoginFailedException("Failed to login", e);
}
});
}

}

Large objects

warning

Do not store large or potentially large objects in the pool plugin.

The pool plugin stores and shares data using the Hazelcast server. Storing large objects can have a negative impact on the network traffic and memory consumption and even cause out-of-memory errors in the Hazelcast server application.

In the pool plugin, it is recommended to use only simple-value objects, such as String, Integer, and so on, wherever possible. Do not use large or potentially large objects in the plugin.