2

I have created an after update trigger on the table as below which invokes the AWS Lambda after active column update.(Followed this aws docs to invoke the lambda)

--**Table creation script**
CREATE TABLE public.groupmember
(
    id integer NOT NULL GENERATED BY DEFAULT AS IDENTITY ( INCREMENT 1 START 1 MINVALUE 1 MAXVALUE 2147483647 CACHE 1 ),
    groupid integer NOT NULL,
    employeeid integer,
    viewid integer,
    enddate timestamp with time zone,
    endby character varying(55) COLLATE public.case_insensitive,
    active boolean GENERATED ALWAYS AS (
CASE
    WHEN (enddate IS NOT NULL) THEN false
    ELSE true
END) STORED,
    test character varying COLLATE pg_catalog."default",
    CONSTRAINT "PK_groupmember" PRIMARY KEY (id),
    CONSTRAINT fk_groupmember_group FOREIGN KEY (groupid)
        REFERENCES public."group" (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE RESTRICT
)

-- **Trigger creation scripts**
CREATE TRIGGER groupmember_update_trigger
    AFTER UPDATE 
    ON public.groupmember
    FOR EACH ROW
    EXECUTE PROCEDURE public.groupmember_update_triggerfn();

-- **Trigger function**
CREATE or replace FUNCTION public.groupmember_update_triggerfn()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE NOT LEAKPROOF
AS $BODY$
Declare
    jsonstring character varying(500);
    jsontosend character varying(500)
    awsarn character varying(300);
BEGIN
    awsarn:='arn:aws:lambda:us-east-1:xyz:function:test-function';
        IF New.active <> Old.active THEN
            IF New.active = false THEN
                    SELECT json_build_object('Action','Delete','Entity','GroupMember','GroupId',New.groupid,'EmployeeId',COALESCE(New.employeeid,-1),'ViewId',COALESCE(New.viewid,-1)) into jsonstring;
              jsontosend := concat('{"body":',jsonstring,'}');
             
             PERFORM payload FROM aws_lambda.invoke(aws_commons.create_lambda_function_arn(awsarn),jsontosend::json,'Event');
            END IF;
        END IF;
            
    RETURN New;
END;
$BODY$;

Here is my Aws Aurora PostgreSQL configuration Image

Consider I have 50 records in the database with active column values as true, and when I update all the records active column value to false and when I try to check the same value in the Lambda it still fetching value as true but should it be false.

Below is my Lambda

const { Pool, Client } = require('pg');
const connectionString = process.env.Conn;
exports.lambdaHandler =  (event, context) => {
         const client = new Client({
          connectionString,
        })
        client.connect();
        client.query('select groupid, employeeid, active from groupmember where groupid = $1 and employeeid = $2',[event.body.GroupId,event.body.EmployeeId], (err, res) => {
            console.log(err);
            console.log("response is");
            console.log(res.rowCount);
            if(res.rowCount>0){
                //this prints true, even the actual value is false.
                console.log(res.rows[0].active);
            }
            client.end();
        })
}

When I delay the thread in Lambda for 5secs or so then it's giving me the updated data without any issue. I am unable to figure out why it's taking time to get the latest data. This is not the case

  1. when I run the Lambda locally.
  2. when I query the active column within the Postgres trigger.

I don't see any replication lag in the metrics. Is there something I need to configure in RDS?

Can someone please help me here?

Any answer would be appreciated, thank you!

SAI RAM
  • 21
  • 2
  • This has to do with transaction isolation. When the lambda function is executed for the first lines you are seeing the version of the table before the execution. If you wait (and the transaction is commited) you'll see the new version. You can see [this question](https://stackoverflow.com/questions/37277313/run-trigger-after-transaction-not-on-each-row-postgresql-9-4) to have some highlights and see the relevant documentation for postgres on this. – NuLo Sep 03 '21 at 18:39
  • @NuLo thanks for the prompt response. Still, I have the same issue even after creating DEFERRABLE INITIALLY constraint on the trigger. Here is my scripts `CREATE CONSTRAINT TRIGGER groupmember_update_trigger AFTER UPDATE ON public.groupmember DEFERRABLE INITIALLY DEFERRED FOR EACH ROW EXECUTE PROCEDURE public.groupmember_update_triggerfn();` I even tried by creating foreign key constraint as described here https://stackoverflow.com/a/16340783/6327087, but no luck – SAI RAM Sep 06 '21 at 17:34
  • I may be missing something but in the trigger I don't see the `jsonstring` being built when there is a modification or there is no modification at all to the active field, but you still call the lambda function. Is this right? – NuLo Sep 07 '21 at 08:33
  • Yes, you are right. I'm invoking the Lambda even when there is no modification to the active field. I moved the Lambda invocation script inside the **if** block and I don't see any improvement in the trigger behavior. – SAI RAM Sep 07 '21 at 10:00
  • That wasn't exactly my question, the problem I see is that in `jsontosend := concat('{"body":',jsonstring,'}');` jsonstring will be null (at least if `New.active = true`) – NuLo Sep 07 '21 at 10:28
  • @NuLo, Sorry for not making it clear in my previous comment. Yes, jsonstring will be null when `New.active = true`. I want to invoke Lambda only when `New.active = false`. I have edited my question to include **jsontosend** line of code inside an if block. I hope it makes sense now. – SAI RAM Sep 07 '21 at 10:57
  • I'm out of ideas, with the `DEFERRABLE INITIALLY DEFERRED` and that change I'm unable to see what can be wrong. – NuLo Sep 09 '21 at 13:01

0 Answers0