hasura / graphql-engine

Blazing fast, instant realtime GraphQL APIs on your DB with fine grained access control, also trigger webhooks on database events.
https://hasura.io
Apache License 2.0
31.13k stars 2.76k forks source link

filters for event triggers or conditional triggers #1241

Open wawhal opened 5 years ago

wawhal commented 5 years ago

Allow setting boolean conditions (like in permissions). One should be able to say things like trigger the webhook only if is_cancelled=false

Use case I came across this while building an online-ordering app in a 3factor style. When is_cancelled in the order table is set to true from the client, you can't stop the event cycle unless you add the filter in all the serverless functions which could complicate things a bit once there are more filters.

It will be cool to have filters on the server itself.

cc: @tirumaraiselvan

tirumaraiselvan commented 5 years ago

:+1:

I think this can be a powerful feature which offloads some of the (serverless) code into a config instead.

@coco98 thoughts?

schettino commented 5 years ago

That is exactly what I'm facing. I'm using a trigger to call a lambda for image manipulation, which saves more info in the same row later on. I need to have a flag to avoid recursion, but the lambda still needs to be called twice. If I could move the check to the Hasura sever, I would save half of executions. Must be different ways to accomplish the same result though, but it's just one use case I wanted to share

tirumaraiselvan commented 5 years ago

@schettino Can you shed more light into the event trigger configuration? I am guessing you are calling the trigger on UPDATE. In that case having specific "listen columns" might be a possible solution to avoid calling the trigger on any update: https://docs.hasura.io/1.0/graphql/manual/event-triggers/create-trigger.html#listen-columns-for-update

schettino commented 5 years ago

It's indeed a possible solution, but there might be another surfaces it might not cover. On my case, I was storing the public image URL, which would trigger the lambda on every update made through the client. However, the url started to change as a step within the Lambda execution and, saving the new url back into that row would trigger its execution again. I could create more columns, like an image id and only listen to its change, but having this sort of filter would be handy, specially for more complex cases than generating thumbnails. What do you think?

tirumaraiselvan commented 5 years ago

@schettino Yes, I agree fully.

hugbubby commented 5 years ago

I have a need for this. Our backend has several mutations that it only needs to be alerted for in the case of a boolean being either true or false. Instead, it gets an alert on updates both ways, which doubles the amount of requests sent between hasura and the microservice for that particular event trigger.

dohomi commented 5 years ago

Totally agree to every one else replied. Best would be to have a similar interface like permissions based on columns of the table to be changed in certain condition. This would reduce the webhook logic and aligns with the setup of Hasura in general

fbrbovic commented 4 years ago

Need this as well, any updates on this?

DblK commented 4 years ago

I saw the change of label 27 days ago, any update about this?

raitucarp commented 4 years ago

Any update? Postgres enum on my database column causes a lot of trigger on the same webook, makes unimportant logs with unsucess responses there.

praveenweb commented 4 years ago

Tracking another related request to Add prevent rule as mentioned here https://github.com/hasura/graphql-engine/issues/5322#issue-652512635 by @revskill10.

BayCo commented 4 years ago

So, how it is going on?

zlanich commented 4 years ago

I also need this. I intend to automatically index records into elastic search, triggered off of create, update and delete events. However, if I wanted to write back to the database in that web hook, it would trigger a loop. I also do not want to waste thousands of lambda executions for no reason. Please!

evancorl commented 4 years ago

This feature has become increasingly important for us due to what seems to be a memory leak with event triggers: https://github.com/hasura/graphql-engine/issues/4077#issuecomment-690153050

zolamk commented 4 years ago

One work around is by editing the trigger function and adding the conditional there like this

create function "notify_hasura_employee_hired_UPDATE"() returns trigger
    language plpgsql
as
$$
DECLARE
    _old record;
    _new record;
    _data json;
  BEGIN
    IF NOT NEW.hiring_confirmed THEN -- this  prevents the event from triggering if the condition is not satisfied
        RETURN NULL;
    end if;
    IF TG_OP = 'UPDATE' THEN
      _old := row((SELECT  "e"  FROM  (SELECT  OLD."hiring_confirmed" , OLD."hiring_confirmed_by" , OLD."hiring_confirmed_on"        ) AS "e"      ) );
      _new := row((SELECT  "e"  FROM  (SELECT  NEW."hiring_confirmed" , NEW."hiring_confirmed_by" , NEW."hiring_confirmed_on"        ) AS "e"      ) );
    ELSE
    /* initialize _old and _new with dummy values for INSERT and UPDATE events*/
      _old := row((select 1));
      _new := row((select 1));
    END IF;
    _data := json_build_object(
      'old', row_to_json(OLD ),
      'new', row_to_json(NEW )
    );
    BEGIN
      IF (TG_OP <> 'UPDATE') OR (_old <> _new) THEN
        PERFORM hdb_catalog.insert_event_log(CAST(TG_TABLE_SCHEMA AS text), CAST(TG_TABLE_NAME AS text), CAST('employee_hired' AS text), TG_OP, _data);
      END IF;
      EXCEPTION WHEN undefined_function THEN
        IF (TG_OP <> 'UPDATE') OR (_old *<> _new) THEN
          PERFORM hdb_catalog.insert_event_log(CAST(TG_TABLE_SCHEMA AS text), CAST(TG_TABLE_NAME AS text), CAST('employee_hired' AS text), TG_OP, _data);
        END IF;
    END;

    RETURN NULL;
  END;
$$;

alter function "notify_hasura_employee_hired_UPDATE"() owner to postgres;

my only problem is how do i make this part of my migration? and how do i ensure hasura doesn't override it? for example re applying the metadata removes the changes i made to the function

osseonews commented 3 years ago

What about finding the Hasura Event trigger you need conditions for by running, select * from information_schema.triggers, and then dropping that trigger, and recreating it via SQL with the appropriate condition? As long as the trigger calls the correct function, how is creating the trigger manually via SQL different than creating it via the Hasura interface? Isn't an Event just a simple trigger calling a specialized function?

robnewton commented 3 years ago

I would also like to see filters added to the Hasura event support. Any plans to tackle this?

tirumaraiselvan commented 3 years ago

I think Postgres's when conditions on triggers might help us achieve this: https://www.postgresql.org/docs/12/sql-createtrigger.html

ilijaNL commented 2 years ago

Any progress?

sachsom95 commented 2 years ago

could we have an update on this

raphaeltm commented 2 years ago

I feel like this becomes particularly interesting with all the latest updates. Between Hasura REST endpoints and transforms in the event payloads, we can do a lot of interesting stuff without needing to spin up anything but Hasura, but conditions would really take that to the next level.

thinknirmal commented 2 years ago

Any update on this please? This feature also saves a lot of resources on the API server by not processing unnecessary events. This becomes significant especially when processing millions of events per day.

sardar1592 commented 1 year ago

This is really critical. Any update? How far are we with this? This is causing a loop in my application.

MistreanuIonutCosmin commented 1 year ago

Hello guys! Really great work so far! I don't want to push, but is there a public roadmap for when the requests are planned to be tackled (or if they will not be)? Having people spam "any updates" for 4 years doesn't build confidence in the product and makes it hard for engineers to push Hasura in their organization.

rahulagarwal13 commented 1 year ago

Thank you everyone for the request and comments for this feature. We would like to inform you that this is on our roadmap but we do not have a timeline at present. Please continue to follow this Github issue. We plan to publish on this issue a detailed RFC that covers all use cases and limitations of the feature. We welcome more detailed feedback from you once we provide those details.

For now it would be useful to understand more about your application/API design that requires filter in event or conditional triggers. @wawhal does provide some information on his 3-factor style online ordering app. Curious to see what other application designs are there to leverage this pattern?

raphaeltm commented 1 year ago

Essentially I think this sort of tooling gives us the beginning of a system to define our own events. Ideally someday we would be able to set a trigger that only runs when a value has changed from A to B, but right now we might have to run every single update to an object through external code.

I think an ideal implementation for me would have two sections: one for the previous state of the object and one for the new state. For insert operations, we would only use the new state section, for delete only the previous state section, and for updates we would use both. Ideally they would both work identically to the permissions definitions, including the ability to traverse relations.

Imagine the following use case. We run a newsletter/blogging platform and want to send out a notification to subscribers of a given author when they publish a post, but only if they have a paid account. We don't want to call our webhook for every change made to the post, only when its status has changed from unpublished to published, and only if the related author account has a paid account flag set. (ideally we could use date functions, but since we can't do that in permissions yet, I won't push it 😂) Only then would the webhook be called.

As I was writing this, I actually had a thought... I think I quite like the idea of defining these conditions as objects called "custom events", rather than in the triggers themselves. I can imagine situations where multiple webhooks should be called for the same conditions. This would allow that. If they are defined as "custom events" though, I think it would also be useful to define them against each of the db events. i.e. The custom "published" event on the blog post table is triggered when:

Hopefully that's helpful @rahulagarwal13 🙂

robnewton commented 1 year ago

I second Raphael's use cases.

We use update events on tables with a status column to trigger an AWS Lambda. It would be our preference, and a lot more cost effective, to check if the conditions on the row are met locally before calling the webhook. We'd save on a large number of Lambda invocations that don't do much other than simply determine there is no processing required, then exit.

We may be able to cover some of the scenarios with condition checks by proxying through some edge function middleware before invoking the Lambda. For criteria that checks anything beyond what is in that triggered table row, we would need to perform a secondary lookup however, which would likely take too long in an edge function. Thus it makes a lot more sense to do all of that condition checks in memory on the Hasura server before the webhook is ever invoked.

Features we'd make use of if they were there:

  1. Upon update, if any column on the listened to table has any one of a list of constant values, then call the webhook, otherwise fail with skipped status.
  2. Upon update, if any column compared to any other column is a match or non-match, then call the webhook, otherwise fail with a skipped status.
  3. Upon update, if any value is less than|greater than|equal to a constant or another column value from the triggered table row, then call the webhook, otherwise fail with a skipped status.
  4. Upon update, if any column on related table rows to the triggered table row has specific values, then call the webhook otherwise fail with skipped status.

Thanks, Rob

On Tue, Dec 20, 2022 at 10:45 AM Raphael Titsworth-Morin < @.***> wrote:

Essentially I think this sort of tooling gives us the beginning of a system to define our own events. Ideally someday we would be able to set a trigger that only runs when a value has changed from A to B, but right now we might have to run every single update to an object through external code.

I think an ideal implementation for me would have two sections: one for the previous state of the object and one for the new state. For insert operations, we would only use the new state section, for delete only the previous state section, and for updates we would use both. Ideally they would both work identically to the permissions definitions, including the ability to traverse relations.

Imagine the following use case. We run a newsletter/blogging platform and want to send out a notification to subscribers of a given author when they publish a post, but only if they have a paid account. We don't want to call our webhook for every change made to the post, only when its status has changed from unpublished to published, and only if the related author account has a paid account flag set. (ideally we could use date functions, but since we can't do that in permissions yet, I won't push it 😂) Only then would the webhook be called.

As I was writing this, I actually had a thought... I think I quite like the idea of defining these conditions as objects called "custom events", rather than in the triggers themselves. I can imagine situations where multiple webhooks should be called for the same conditions. This would allow that. If they are defined as "custom events" though, I think it would also be useful to define them against each of the db events. i.e. The custom "published" event on the blog post table is triggered when:

  • on insert: conditions X are satisfied
  • on update: conditions Y are satisfied
  • on delete: "off"

Hopefully that's helpful @rahulagarwal13 https://github.com/rahulagarwal13 🙂

— Reply to this email directly, view it on GitHub https://github.com/hasura/graphql-engine/issues/1241#issuecomment-1359589788, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAJSXIFZ5CGMW6JWH2PSOKTWOHH7ZANCNFSM4GLJQZ7A . You are receiving this because you commented.Message ID: @.***>

cfurlong0018 commented 1 year ago

Is there an update on this? This'd be really valuable for our use case as well. Would it be easier to tap into what Hasura already has for transforms etc. and allow us to codify filters?

DavidParker682 commented 1 year ago

How about allowing Computed Fields to act as Event triggers? This would allow the user full control over the the trigger condition.

In my use case, I have an 'event' that should trigger an action when 25% of tickets are sold. I have a computed field for 'openToPublic' which is boolean. It would be great if I could trigger the Event when this computed field switches to true.

Jaykob commented 1 year ago

5 years have passed. I think we won't see this happening :(

lludovic commented 1 year ago

This would be a killer feature, for all the reason that have aleady mentioned above and alose:

Kaniok commented 8 months ago

Would be nice to have this feature. You can quite easyli do most of them with postgresql triggers it is not hard, but i need user id from the hasura which make this impossible make by just postgresql. The permissions are in hasura greate but make it hard to go around. Hope to atleast show need for this feature.

Bessonov commented 8 months ago

Would be nice to have this feature. You can quite easyli do most of them with postgresql triggers it is not hard, but i need user id from the hasura which make this impossible make by just postgresql. The permissions are in hasura greate but make it hard to go around. Hope to atleast show need for this feature.

Try:

CREATE FUNCTION getUserId() RETURNS uuid AS $$
BEGIN
  RETURN (current_setting('hasura.user')::jsonb->>'x-hasura-user-id')::uuid;
END; $$ LANGUAGE plpgsql;

Not sure it will work in your context.

Kaniok commented 8 months ago

@Bessonov Thank you very much i have already tried this many times but i didn´t used conversions so it didn´t work.

Naik1994 commented 8 months ago

Hi Team,

Can anybody provide an update on this feature request? Is this currently in the roadmap or not? Will it be released in any upcoming release? This request has been pending for a long time, and we would appreciate any information or updates. Thank you.

xta commented 7 months ago

+1 for conditional triggers with environment variables (discussed here https://github.com/hasura/graphql-engine/issues/5322)