You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The new option trigger allows to create persistent triggers. The
option can be a string or an array of strings - name (or names) of the
event in which the trigger will be set.
Each function created with box.schema.func.create has its own tuple
in system space _func. When the tuple with non-empty field trigger
is inserted, the function is set to the events listed by this option
in the event registry, function name is used as a trigger name. When
such tuple is deleted from _func, the triggers are deleted.
When a function is created, it is set as a trigger without any checks -
it can replace an existing one. When it is deleted, it can delete a
trigger it hasn't set - for example, it can happen when user manually
replaces a persistent trigger. So, it is recommended to have different
names (or even separate namespaces) for persistent and usual triggers.
When a function is called as a trigger, access rights are ignored, so,
actually, every user that can trigger the event has access to your
function, but only as a trigger.
Since the space _func is not temporary, after Tarantool is restarted,
the persistent triggers will be set. Also, since the space is not local,
the persistent triggers will be replicated, so user has to manually
control that triggers (for example, before_replace or before_commit)
are run only on master node, if the application requires such logic.
Example of a persistent trigger on a single node:
box.cfg{}
-- Create spacesbox.schema.space.create('cdc')
box.space.cdc:create_index('pk')
box.schema.space.create('my_space1')
box.space.my_space1:create_index('pk')
box.schema.space.create('my_space2')
box.space.my_space2:create_index('pk')
-- Set triggerslocalbody='function(old, new) box.space.cdc:auto_increment{old, new} end'localevents= {
'box.space.my_space1.on_replace',
'box.space.my_space2.on_replace'
}
-- Set the function as a trigger for two events at the same time.box.schema.func.create('example.space_trigger', {body=body, trigger=events})
-- Some replacesbox.space.my_space1:replace{0, 'v1'}
box.space.my_space2:replace{0, 0}
box.space.my_space1:replace{0, 'v2'}
box.space.my_space2:replace{0, 1}
print(box.space.cdc:fselect{})
Here, restart Tarantool to check if the trigger will be restored.
Example of a persistent trigger in a cluster. In this scenario,
before_replace trigger is not idempotent, so it must be applied
only once - on actual replace, but not during replication. For this
purpose, box.session.type() can be used.
-- instance1.lualocalfiber=require('fiber')
box.cfg{}
box.schema.user.grant('guest', 'super')
localbody=[[ function(old_tuple, new_tuple) -- Covert kilogramms into gramms if box.session.type() ~= 'applier' then return box.tuple.new{new_tuple[1], new_tuple[2] * 1000} end end]]localevent='box.space.weights.before_replace'box.schema.func.create('example.replicated_trigger', {body=body, trigger=event})
box.schema.space.create('weights')
box.space.weights:format({
{name='name', type='string'},
{name='gramms', type='unsigned'},
})
box.space.weights:create_index('primary', {parts= {'name'}})
box.cfg{listen=3301, replication= {3301, 3302}}
box.ctl.wait_rw()
box.space.weights:replace{'elephant', 4000}
box.space.weights:replace{'crocodile', 600}
-- Wait for another instancewhilebox.space.weights:count() ~=4dofiber.sleep(0)
endprint(box.space.weights:fselect{})
```luaAnotherinstance:
```lua-- instance2.lualocalfiber=require('fiber')
box.cfg{listen=3302, replication= {3301, 3302}}
box.ctl.wait_rw()
box.space.weights:replace{'cat', 6}
box.space.weights:replace{'dog', 10}
-- Wait for another instancewhilebox.space.weights:count() ~=4dofiber.sleep(0)
endprint(box.space.weights:fselect{})
We see that the trigger was applied exactly once for each tuple.
I would also point out that when the trigger is fired, it pins the
function, so it's better not to use persistent triggers for intensive
events if the trigger yields (if the trigger doesn't yield, the problem
won't be encountered at all). But if one faced such problem, he can
manually drop the trigger from module trigger, wait for a while for
the trigger to finish its execution and only then drop the function.
Requested by @ drewdzzz in tarantool/tarantool@4c81aba.
The text was updated successfully, but these errors were encountered:
Uh oh!
There was an error while loading. Please reload this page.
Related dev. issue(s): tarantool/tarantool#8663
Related doc. issue(s): #3988
Product: Tarantool
Since: 3.1
Root document: https://www.tarantool.io/en/doc/latest/reference/reference_lua/box_schema/func_create/
SME: @ drewdzzz
Details
The new option
trigger
allows to create persistent triggers. Theoption can be a string or an array of strings - name (or names) of the
event in which the trigger will be set.
Each function created with
box.schema.func.create
has its own tuplein system space
_func
. When the tuple with non-empty fieldtrigger
is inserted, the function is set to the events listed by this option
in the event registry, function name is used as a trigger name. When
such tuple is deleted from
_func
, the triggers are deleted.When a function is created, it is set as a trigger without any checks -
it can replace an existing one. When it is deleted, it can delete a
trigger it hasn't set - for example, it can happen when user manually
replaces a persistent trigger. So, it is recommended to have different
names (or even separate namespaces) for persistent and usual triggers.
When a function is called as a trigger, access rights are ignored, so,
actually, every user that can trigger the event has access to your
function, but only as a trigger.
Since the space
_func
is not temporary, after Tarantool is restarted,the persistent triggers will be set. Also, since the space is not local,
the persistent triggers will be replicated, so user has to manually
control that triggers (for example,
before_replace
orbefore_commit
)are run only on master node, if the application requires such logic.
Example of a persistent trigger on a single node:
Here, restart Tarantool to check if the trigger will be restored.
The output shows that all replaces were captured.
Example of a persistent trigger in a cluster. In this scenario,
before_replace trigger is not idempotent, so it must be applied
only once - on actual replace, but not during replication. For this
purpose,
box.session.type()
can be used.Output of both instances:
We see that the trigger was applied exactly once for each tuple.
I would also point out that when the trigger is fired, it pins the
function, so it's better not to use persistent triggers for intensive
events if the trigger yields (if the trigger doesn't yield, the problem
won't be encountered at all). But if one faced such problem, he can
manually drop the trigger from module
trigger
, wait for a while forthe trigger to finish its execution and only then drop the function.
Requested by @ drewdzzz in tarantool/tarantool@4c81aba.
The text was updated successfully, but these errors were encountered: