Bonita - How to skip tasks execution - bonita

I'm developing a bonita process to run in a Bonita Enterprise instance. I need to use a custom actor filter on each task, for selecting possible approvers.
Each actor is mapped to a role
Each user has at least one membership with a role and a group
Some users have at least two memberships with the same role and two different groups
My actor filter, based on configuration, can match users belonging to one or two groups and the role associated with the actor.
Everything is fine until here, but...
I may have no available approvers for the task, so I need to skip it. Everything seems to be fine again, but here comes my issue:
when I try to skip the task, execution fails because there is no input for the task:
2020-03-10 17:52:24.233 +0000 SEVERE: org.bonitasoft.engine.execution.work.InSessionBonitaWork THREAD_ID=89 | HOSTNAME=xxx | TENANT_ID=1 | org.bonitasoft.engine.expression.exception.SExpressionEvaluationException : "PROCESS_DEFINITION_ID=8625658402299344846 | PROCESS_NAME=xxx | PROCESS_VERSION=1.0 | PROCESS_INSTANCE_ID=2003 | ROOT_PROCESS_INSTANCE_ID=2003 | FLOW_NODE_DEFINITION_ID=7701602949247176053 | FLOW_NODE_INSTANCE_ID=40011 | FLOW_NODE_NAME=Task Name | Some data were not found [inputAction]"
org.bonitasoft.engine.expression.exception.SExpressionEvaluationException: PROCESS_DEFINITION_ID=8625658402299344846 | PROCESS_NAME=xxx | PROCESS_VERSION=1.0 | PROCESS_INSTANCE_ID=2003 | ROOT_PROCESS_INSTANCE_ID=2003 | FLOW_NODE_DEFINITION_ID=7701602949247176053 | FLOW_NODE_INSTANCE_ID=40011 | FLOW_NODE_NAME=Task Name | Some data were not found [inputAction]
at org.bonitasoft.engine.expression.DataExpressionExecutorStrategy.evaluate(DataExpressionExecutorStrategy.java:112)
at org.bonitasoft.engine.expression.impl.ExpressionServiceImpl.evaluate(ExpressionServiceImpl.java:154)
at org.bonitasoft.engine.core.expression.control.api.impl.ExpressionResolverServiceImpl.evaluateExpressionsOfKind(ExpressionResolverServiceImpl.java:225)
at org.bonitasoft.engine.core.expression.control.api.impl.ExpressionResolverServiceImpl.evaluateAllExpressionsWithNoDependencies(ExpressionResolverServiceImpl.java:182)
at org.bonitasoft.engine.core.expression.control.api.impl.ExpressionResolverServiceImpl.evaluateExpressionsFlatten(ExpressionResolverServiceImpl.java:115)
at org.bonitasoft.engine.core.expression.control.api.impl.ExpressionResolverServiceImpl.evaluate(ExpressionResolverServiceImpl.java:83)
at org.bonitasoft.engine.execution.transition.TransitionConditionEvaluator.evaluateCondition(TransitionConditionEvaluator.java:44)
at org.bonitasoft.engine.execution.transition.ImplicitGatewayTransitionEvaluator.evaluateTransition(ImplicitGatewayTransitionEvaluator.java:73)
at org.bonitasoft.engine.execution.transition.ImplicitGatewayTransitionEvaluator.evaluatedTransitions(ImplicitGatewayTransitionEvaluator.java:66)
at org.bonitasoft.engine.execution.transition.ImplicitGatewayTransitionEvaluator.evaluateTransitions(ImplicitGatewayTransitionEvaluator.java:42)
at org.bonitasoft.engine.execution.TransitionEvaluator.evaluateOutgoingTransitionsForActivity(TransitionEvaluator.java:80)
at org.bonitasoft.engine.execution.TransitionEvaluator.evaluateOutgoingTransitions(TransitionEvaluator.java:66)
at org.bonitasoft.engine.execution.TransitionEvaluator.buildTransitionsWrapper(TransitionEvaluator.java:126)
at org.bonitasoft.engine.execution.ProcessExecutorImpl.executeValidOutgoingTransitionsAndUpdateTokens(ProcessExecutorImpl.java:698)
at org.bonitasoft.engine.execution.ProcessExecutorImpl.childFinished(ProcessExecutorImpl.java:588)
at org.bonitasoft.engine.execution.ContainerRegistry.nodeReachedState(ContainerRegistry.java:58)
at org.bonitasoft.engine.execution.work.NotifyChildFinishedWork.work(NotifyChildFinishedWork.java:69)
at org.bonitasoft.engine.execution.work.TxBonitaWork.lambda$work$0(TxBonitaWork.java:42)
at org.bonitasoft.engine.transaction.JTATransactionServiceImpl.executeInTransaction(JTATransactionServiceImpl.java:274)
at org.bonitasoft.engine.execution.work.TxBonitaWork.work(TxBonitaWork.java:42)
at org.bonitasoft.engine.execution.work.LockProcessInstanceWork.work(LockProcessInstanceWork.java:63)
at org.bonitasoft.engine.execution.work.failurewrapping.TxInHandleFailureWrappingWork.work(TxInHandleFailureWrappingWork.java:41)
at org.bonitasoft.engine.execution.work.failurewrapping.TxInHandleFailureWrappingWork.work(TxInHandleFailureWrappingWork.java:41)
at org.bonitasoft.engine.execution.work.failurewrapping.TxInHandleFailureWrappingWork.work(TxInHandleFailureWrappingWork.java:41)
at org.bonitasoft.engine.execution.work.InSessionBonitaWork.work(InSessionBonitaWork.java:59)
at org.bonitasoft.engine.work.BonitaThreadPoolExecutor.lambda$submit$1(BonitaThreadPoolExecutor.java:132)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
all tasks have a contract input with a text variable inputAction with values "approved" or "rejected".
I tried to
return an empty list of user IDs, but instantiation fails because the actor filter returns no users;
return an empty list of user IDs and skip the task with a "Catch error" attached to the task, but the task is not skipped (exception above);
throw a UserFilterException, but the task is not skipped (exception above);
use default action, but the task is not skipped (exception above).
Is there a way to accomplish this?

The issue was due to the use of local variables ti process approvers actions. Those variables were not created yet at the moment of failure, so It was not possibile to skip the task (bug?). Moving to pool variables solved my issue.

Related

How to list all parameters in Postgres?

I was wondering if there's a parameter for the currently authenticated psql user?
But then I wonder a more broader question - how can I just see what all the paremeters are?
I might discover some interesting parameters if I could see a whole list of them?
I'm only seeing online how to get the value of one parameter. Not a list...
Alvaro has answered the question how to list your current parameter values.
To get the authenticated user, you can call the SQL function session_user:
SELECT session_user;
The currently effective user can be seen with
SELECT current_user;
In psql, you can see details about your current database session with
\conninfo
Nonsense. Try these two SQL statements:
set foo.bar =42;
and then:
select current_setting('foo.bar');
You’ve just set, and read an entity that the PostgreSQL doc doesn’t seem to name. You might call x.y a “user-defined session parameter”. Where is its value held? Server-side, of course.
I too would like to know how to list the names of all currently defined such entities—system-defined, like TimeZone, and user-defined.
— bryn#yugabyte.com
PostgreSQL does not have such a thing as server-side session variables, so it's not clear what you are asking about.
Some PLs (such as PL/Python, PL/Perl) have session variables (%_SHARED in PL/Perl, GD and SD in PL/Python for example), but they are internal to the PL, not part of the server proper.
psql also has variables, which you can set with \set, and you can get a list with the same command. I suppose that's not what you want though.
Maybe you refer to so-called custom GUC configuration parameters, which are sometimes abused as session variables. You can get a list of those using SHOW ALL or SELECT * FROM pg_catalog.pg_settings.
SHOW ALL below can show all parameters according to the documentation:
SHOW ALL;
This is how SHOW ALL works below:
postgres=# SHOW ALL;
name | setting | description
----------------------------+-------------+------------------------------------------------------------------------------------------
allow_in_place_tablespaces | off | Allows tablespaces directly inside pg_tblspc, for testing.
allow_system_table_mods | off | Allows modifications of the structure of system tables.
application_name | psql | Sets the application name to be reported in statistics and logs.
archive_cleanup_command | | Sets the shell command that will be executed at every restart point.
archive_command | (disabled) | Sets the shell command that will be called to archive a WAL file.
archive_mode | off | Allows archiving of WAL files using archive_command.
archive_timeout | 0 | Forces a switch to the next WAL file if a new file has not been started within N seconds.
array_nulls | on | Enable input of NULL elements in arrays.
authentication_timeout | 1min | Sets the maximum allowed time to complete client authentication.
autovacuum | on | Starts the autovacuum subprocess.
...
And, you can show one specific parameter with SHOW as shown below:
postgres=# SHOW allow_in_place_tablespaces;
allow_in_place_tablespaces
----------------------------
off
(1 row)
But, you cannot show more than one parameters with SHOW as shown below:
postgres=# SHOW allow_in_place_tablespaces, allow_system_table_mods;
ERROR: syntax error at or near ","
LINE 1: show allow_in_place_tablespaces, allow_system_table_mods;
So to show more than one parameters, use SELECT FROM pg_settings below:
postgres=# SELECT name, setting, short_desc FROM pg_settings WHERE name IN ('allow_in_place_tablespaces', 'allow_system_table_mods');
name | setting | short_desc
----------------------------+---------+------------------------------------------------------------
allow_in_place_tablespaces | off | Allows tablespaces directly inside pg_tblspc, for testing.
allow_system_table_mods | off | Allows modifications of the structure of system tables.
(2 rows)
In addition, current_setting() can show one specific parameter as shown below:
postgres=# SELECT current_setting('allow_in_place_tablespaces');
current_setting
-----------------
off
(1 row)
But, you cannot show more than one parameters with current_setting() as shown below:
postgres=# SELECT current_setting('allow_in_place_tablespaces', 'allow_system_table_mods');
ERROR: invalid input syntax for type boolean: "allow_system_table_mods"
LINE 1: ...ECT current_setting('allow_in_place_tablespaces', 'allow_sys...

Question about PostgreSQL performance tables

I am working on redesigning a service to optimize it and I don't know which option to choose for a table.
I have two tables with many entries.
Table 1: logs (10M rows)
Table 2: user_agents (2M rows)
logs
+----+-----+---------------+-----+
| id | ... | user_agent_id | ... |
+----+-----+---------------+-----+
user_agents
+----+------+
| id | name |
+----+------+
Currently my table logs have a user_agent_id to go directly to the user_agent associated with the logs of a user's visit.
When a new visitor sends logs before saving them in the database I check that this user agent is already in the user_agent table otherwise I add it.
As long as the logs are not registered in the database, the user does not have access to the page he wants.
I would like to optimize the writing speed in the logs table and I would like to know if the fact of having separated its data into 2 tables is really significant in terms of writing time.
The alternative would be to put a user_agent column back into the logs table.
Fontion to get id/insert user_agent :
public function get_ua_id($headers)
{
return ListUA::firstOrCreate(['name' => isset($headers['HTTP_USER_AGENT']) ? utf8_encode($headers['HTTP_USER_AGENT']) : '']);
}

Designing a caching layer in front of a DB with minimal number of queries

I have multiple jobs that work on some key. The jobs are ran asynchronously and are written to some write-behind cache. Conceptually it looks like this:
+-----+-----------+----------+----------+----------------+
| key | job1 | job2 | job3 | resolution |
+-----+-----------+----------+----------+----------------+
| 123 | job1_res | job2_res | job3_res | resolution_val |
+-----+-----------+----------+----------+----------------+
The key concept is that I don't know in advance how many jobs are running. Instead, when it's time to write the record we add our "resolution" (based on the current job results we've got) and write all values to the DB (MongoDB if that's matter)
I also have a load() function that runs in case of a cache-miss. What it does is to fetch the record from the database, or creating a new (and empty) one if the record wasn't found.
Now, there's a time window where the record isn't in the cache nor in the database. In that time, a "slow worker" might write its result, and unluckily the load() function will create a new record.
When evacuated from the cache, the record will look like this:
+-----+----------+-------------------------------+
| key | job4 | resolution |
+-----+----------+-------------------------------+
| 123 | job4_val | resolution_based_only_on_job4 |
+-----+----------+-------------------------------+
I can think of two ways to control this problem:
Configure the write-behind mechanism so it will wait for all jobs to complete (i.e. give sufficient amount of time)
On write event, first query the DB for the record and merge results.
Problems with current solutions:
Hard to calibrate
Demands an extra query for write operation
What's the most natural solution to my problem?
Do I have to implement solution #2 in order to guarantee a resolution on all job results?
EDIT:
Theoretically speaking, I think that even after implementing solution #2 it doesn't give us the guarantee that the resolution will be based on all job results.
EDIT2:
If the write-behind mechanism guarantees order of operations then solution #2 is ok. This can be achieved by limiting the write-behind to one thread.

Database logic for user achievments

I have a table in my database that stores users, for example:
userID | userName | email | password | wins | losses | exp
Now I want the user to be able to get achievments in my game, like "win 5 games in a row", and I obviously want that progress in the database (Google app-engine) so progress is not lost when user exits client. Example of achievment table:
achievmentID | achievmentTitle | description | reward
Now how would I go about saving achievment progress for each user in the best manner? I need to save both progress (like 3/5 games in a row won) and if achievment is completed or not.
The product is for Android/iOS and uses google app engine (datastore) as database.
The way you set up your table would not be very efficient. In my mind to be the most efficient, you would have to make a new column on your users table (not new table, but after the 'exp') and create a sort of key for achievements. For example, you could give each achievement an ID (which you would keep track of like in a notes on notepad or something).
Then, when they get that achievement, you would put "123/" and if you did another achievement, it would say something like "123/461/".
Then you could make a script that breaks apart these IDs to see what achievements have been completed.

NodeJS Periodic tasks

Firts of all, I'll explain my problem:
I'm developing an ecommerce website. One of it features is the possibility for the customers to create purchasing rules. With these rules a customer can set a start date, a periodicity and a product to purchase. The result is that the product will be purchased every [periodicity] days from [start date].
The system is developed with NodeJS as back-end, MongoDB as database and AngularJS as front-end.
I've found some projects for scheduling tasks in NodeJS. Two of them are:
node-schedule
node-cron
Both of them are great tools but I have the same problem with the two of them. The problem is that I need to create scheduled tasks as well as stop them. With these tools is very clear how to schedule a function to be executed over time, but how can I stop them at any moment?
The objects provided by node-schedule and node-cron have a cancel() or stop() method to stop the scheduling, but to invoke that method I need to have the object.
My question is if there is a way to "store" the scheduled tasks in database in order to be able to stop them at any moment and from anywhere other than the function they were created.
And if this is not possible, if there is another tool better than those I've mentioned to do what I need.
Thank you very much for reading and any help would be appreciated.
Ok, I've found a better solution for my problem than adding a bunch of scheduled task, one for purchasing rule. Now my purchasing_rules table looks like this:
+--------------------+
| purchase_rules |
+--------------------+
| customer_id |
| product_id |
| quantity |
| start_date |
| periodicity (Days) |
+--------------------+
My solution is to add the field next run, so my table will look like:
+--------------------+
| purchase_rules |
+--------------------+
| customer_id |
| product_id |
| quantity |
| start_date |
| periodicity (Days) |
| next_run |
+--------------------+
By default [next_run] will be [start_date] + [periodictiy].
And now, the magic:
I will use node-schedule to schedule a job every day at a certain hour. That job will do the following:
Look in the purchase_rules table for any rule whose next_run = today
For every rule found:
Purchase the desired [quantity] of product [product_id] for the customer [customer_id]
Make [next_run] = [next_run] + [periodicity]
Finish
This way the database will not be accesed as many times as with the Agenda package and for "stopping" a purchasing_rule I only have to remove it from database.
I hope someone will find this useful some day.

Resources