Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Valkey triggers proposal #9

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open

Conversation

ranshid
Copy link
Member

@ranshid ranshid commented Sep 16, 2024

This is a proposal to introduce Valkey Triggers.
Valkey triggers are persistent procedures which are executed in response to some keyspace event.
Today Valkey keyspace Notifications offer the ability to publish events to dedicated pub/sub channels.
Valkey triggers add the ability to place extending logic on such keyspace events and to localize actions on the server side reducing the need to monitor and react to events on the application side.
We propose to extend the existing Valkey Functions with the ability to define trigger function call on specific keyspace event.
As being integrated in the Valkey Functions infrastructure, Triggers are persisted as part of the user data.

Signed-off-by: Ran Shidlansik <[email protected]>
Signed-off-by: Ran Shidlansik <[email protected]>
Signed-off-by: Ran Shidlansik <[email protected]>
Triggers.md Outdated Show resolved Hide resolved
@madolson madolson added the draft This RFC needs to be reviewed by the TSC label Sep 30, 2024
Triggers.md Outdated Show resolved Hide resolved
Triggers.md Outdated Show resolved Hide resolved
Triggers.md Outdated Show resolved Hide resolved
Triggers.md Outdated Show resolved Hide resolved
Triggers.md Outdated Show resolved Hide resolved
"total_duration" - the aggregated total duration time this trigger run

*** Open question ***
should `CONFIG RESETSTAT` also reset the triggers statistics, or should that only be done when functions lib is reloaded?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they should be reset at the same time that function-statistics are reset.

Triggers.md Outdated Show resolved Hide resolved
### Debug mechanism

While Valkey functions and scripts are executed as part of the FCALL/EVAL calls, it is thus possible to report the errors back to the calling client.
Triggers, however, are silently executing which makes it hard for the user to understand why the trigger did not work and what errors occurred during execution of the trigger.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this context I take the user to be a developer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

Triggers.md Outdated Show resolved Hide resolved
1. All error msgs will be intercepted as deferred errors (much like modules do).
2. After trigger completes run, in case errors were issues, it will update the stats with the num,ber of errors.
3. The trigger will report the errors to a dedicated channel in the following structure:
`__triggers@errors__:<trigger-name>`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't the log sufficient?

Based on how errors are counted, it seems that a triggered function might attempt to report an error that should be delivered to the client. This suggests that the message will not normally be delivered. What would be delivered?

I have not worked with LUA or EVAL in the past. It seems likely that the answers to some of my questions would be obvious if I had. Please point me at any reading you think would help.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the trigger execution is hidden from the user we cannot just return it as an error.

For the case when the trigger is issued based on internal events (eg evictions) there is no request context to issue the error to.
For case were the event was issued as part of the complex command flow (eg script or transaction),
we have 2 options to consider trigger execution:

  1. without breaking the action atomicity (in which case the trigger will be executed AFTER the command was executed) in which case the response to the command was already sent or written to the COB, so not much point or ability to return it to the client.
  2. we can execute the trigger as soon as the event is reported, practically breaking the atomicity and in this case I agree there is a problem we need to consider how to handle trigger failure, since it potentially already changed the data.

@madolson madolson requested a review from stockholmux October 4, 2024 02:08
Copy link
Member

@stockholmux stockholmux left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First, let me say on on the record of conceptually likely stored procedures and triggers. I also find Lua to be fun and useful. I'm not sold on the combination described here though.

Second, While I personally like Lua, that being the only engine limits it for a lot of users.

Third, the sections about atomicity, recursive, and ACLs in this doc reveal how tricky it is to get this to work in the context of Valkey. The complexity in each of these makes this tricky to navigate for users in balancing security, stability, and data guarantees: someone attempting to use this is very likely to get it wrong and unwittingly sacrifice something they didn't intend.

Might the goals of triggers be accomplished by some other means: maybe a persistent keyspace notification mechanism? Perhaps hook interface to another runtime that would prove to be more flexible? There are some good inspirations for these in other NoSQL databases that might work here.

As stated before, a trigger is basically a specific engine function.
The function synopsis will be identical for all triggers which will get the following parameters:

**a. key -** the key for which the event was triggered
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I'm a little confused here. It appears that you're using something different from the keyspace/keyevent notification format? Why not the same?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The event description is identical to the channel name used to report the keyspace events.

### Atomicity and triggers

All keyspace events are triggered immediately after the operation which triggered them. If we allow the triggers to be executed when the keyspace event has been triggered,
It means allowing a write call performed in the middle of operating another command. Another (technical) issue is related to nested scripts. Currently there is a [protection](https://github.com/valkey-io/valkey/blame/unstable/src/script_lua.c#L891) in Valkey code preventing to execute lua script from a scripts.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this work with [WATCH]MUTLI/EXEC? Does it interrupt a transaction?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was hoping to discuss this section. IMO we should NOT break atomicity with triggers, although this was the way I implemented the PoC. allowing triggers during scripts and transactions can indeed lead to much confusion but alternatively, queuing them and allow them to be executed after the transaction can be problematic since the trigger context might be lagging behind the data. I agree this part is the most problematic.

Since Redis triggers are built on keyspace events, the DB scope will be the same as the keyspace event was issued on.

#### ACL User scope
By default the scope of the user will by the superuser which will not be limited by any authentication restrictions.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should default to least privilege rather than greatest.

the name of the ACL user to attach to the trigger run context.

### New Commands
1. `CLIENT TRIGGERS [ON|OFF]` new subcommand. Sometimes it will be required to mute trigger execution in some context (say administrative fix to the dataset)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All or nothing? What if someone wanted to disable some triggers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can extend this in the future if we want. the point of this ability is that the developer/admin wants to access the data and have no interference of triggers while doing so.

Triggers.md Outdated

### Triggers as part of function libraries
Valkey triggers will be implemented as an extension of the Valkey [Function Libraries](https://valkey.io/topics/functions-intro/) .
A trigger is basically a Valkey function which will be called when some specific keyspace event was issued.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are triggers limited only to keyspace events? Could you also trigger on an event through some arbitrary channel/pattern?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SO I thought of the keyspace events since they are already defined and known to users, so I think it would make it easier for users to adopt. I am open to other suggestions.


Here is an example library code to schedule tasks to be executed after/every several seconds

![image](https://user-images.githubusercontent.com/88133677/225652613-aa85beee-05f1-4c5e-abe7-1d334b0e882f.png)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes please. The use of images is also inaccessible.

ranshid and others added 8 commits October 9, 2024 14:31
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
@ranshid
Copy link
Member Author

ranshid commented Oct 9, 2024

.

@ranshid ranshid closed this Oct 9, 2024
@ranshid ranshid reopened this Oct 9, 2024
@ranshid
Copy link
Member Author

ranshid commented Oct 9, 2024

First, let me say on on the record of conceptually likely stored procedures and triggers. I also find Lua to be fun and useful. I'm not sold on the combination described here though.

thank you @stockholmux. Can you tell me what in the combination blocks you?

Second, While I personally like Lua, that being the only engine limits it for a lot of users.

While I might agree, LUA is still a very efficient engine. Also I find this out of scope of this discussion. in case we add more engines the support for the triggers will still be there.

Third, the sections about atomicity, recursive, and ACLs in this doc reveal how tricky it is to get this to work in the context of Valkey. The complexity in each of these makes this tricky to navigate for users in balancing security, stability, and data guarantees: someone attempting to use this is very likely to get it wrong and unwittingly sacrifice something they didn't intend.

I agree about atomicity. this is a challenge but lets be honest - it is not kids who are playing with Valkey - it is usually developers that can be thought to consider the actions they are placing. the execution will still be serialized and the developer can just as well shoot himself in the lag while communicating several clients to the same Valkey server.

Might the goals of triggers be accomplished by some other means: maybe a persistent keyspace notification mechanism? Perhaps hook interface to another runtime that would prove to be more flexible? There are some good inspirations for these in other NoSQL databases that might work here.

Sure It can. We can introduce timers which would help in many of the described cases.
However I think there will always be a usecase where someone wants to impact the data in a new way and will not have the feature in place.

ranshid and others added 8 commits October 9, 2024 15:01
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
ranshid and others added 19 commits October 9, 2024 15:25
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Madelyn Olson <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
Co-authored-by: Daniel House @ Seeking Opportunities <[email protected]>
Signed-off-by: ranshid <[email protected]>
@ranshid
Copy link
Member Author

ranshid commented Oct 9, 2024

@stockholmux @daniel-house I would like to thank you for spending the time reviewing this!
Sorry I was only able to address some of your comments today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
draft This RFC needs to be reviewed by the TSC
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants