简体   繁体   English

Postgres pg_notify 不会通知何时从通过 Timescaledb 操作的作业调度程序调用的存储过程更新表

[英]Postgres pg_notify does not notify when a table gets updated from a stored procedure that is called via the Timescaledb Action's job scheduler

I have two tables in my Postgres DB.我的Postgres DB 中有两个表。 Table A is where all the data is stored.表 A 是存储所有数据的地方。 A stored procedure (X) does some aggregation of the data in Table A and has insert/update statement for Table B. Using the Timescaledb Actions's job scheduler, every 1 hour X is called and table B gets updated or a new data is inserted in it.存储过程 (X) 对表 A 中的数据进行了一些聚合,并对表 B 具有插入/更新语句。使用Timescaledb Actions 的作业调度程序,每 1 小时调用一次 X 并更新表 B 或插入新数据它。 I have another trigger (T) that is triggered every time Table B gets updated or when a new record is inserted in it, the trigger simply PERFORM pg_notify('channel',payload) .我有另一个触发器(T),每次更新表 B 或在其中插入新记录时都会触发,触发器只是PERFORM pg_notify('channel',payload) Python backend receives the notification by executing Listen command from the psycopg2 . Python 后端通过执行来自psycopg2Listen命令接收通知。

When I try to INSERT/UPDATE with random data in Table B, Python receives the Notification.当我尝试使用表 B 中的随机数据INSERT/UPDATE时,Python 会收到通知。 But Python does not receives any notification when Stored Procedure update/inserts in Table B. The trigger (T) is not triggered when Table B gets updated or inserted from the Stored Procedure X.但是当存储过程在表 B 中更新/插入时,Python 没有收到任何通知。当从存储过程 X 更新或插入表 B 时,不会触发触发器 (T)。

I have read the Notify documentation.我已阅读通知文档。 But I am sure I might have missed something important.但我确信我可能错过了一些重要的事情。 If anyone could help me with this, I will be grateful.如果有人可以帮助我,我将不胜感激。

--TRIGGER FUNCTION TO NOTIFY 
CREATE FUNCTION newDataTableB() RETURNS trigger AS $$
DECLARE
    rec RECORD;
    payload TEXT;
BEGIN   
    rec := new;
    payload := json_build_object(TG_OP, rec.id);
    -- Notify the channel
    PERFORM pg_notify('db_notifications', payload);
    RETURN rec;
END;
$$ LANGUAGE plpgsql;

-- TRIGGER ON TABLE B
CREATE TRIGGER newDataTableB_tr AFTER INSERT OR UPDATE ON tableB FOR EACH ROW EXECUTE PROCEDURE newDataTableB();


--Stored Procedure 
CREATE OR REPLACE PROCEDURE insertIntoTableB(job_id int, config jsonb) LANGUAGE PLPGSQL AS $$
DECLARE
    rec_findSpeed record;
    cur_findSpeed refcursor;
BEGIN
    --materialized view to find average of Speed stored in table A that is group by trip_id 
    REFRESH MATERIALIZED VIEW findSpeed;

    open cur_findSpeed for SELECT * from findSpeed;
    loop
        fetch cur_findSpeed into rec_findSpeed;
        exit when not found;
        
        IF EXISTS (SELECT * FROM tableB WHERE trip_id = rec_findSpeed.trip_id) THEN
            update tableB set averageSpeed=rec_findSpeed.averageSpeed, min_time = rec_findSpeed.min_time where trip_id = rec_findSpeed.trip_id;
        ELSE
            INSERT into tableB(averageSpeed, min_time, trip_id)
            values(rec_findSpeed.averageSpeed, rec_findSpeed.min_time, rec_findSpeed.trip_id)
        END IF;
    end loop;
    close cur_findSpeed;
END;
$$;
SELECT add_job('insertIntoTableB','1h');


-- MATERIALIZED VIEW
    CREATE MATERIALIZED VIEW findSpeed AS
    SELECT AVG(speed) as averageSpeed, trip_id, min(time) as min_time
    FROM tableA
    GROUP BY trip_id
    WITH DATA;

Python code as requested. Python 代码按要求。 The Python backend requires to execute some other queries after it receives the notification. Python后端收到通知后需要执行一些其他的查询。 I followed the psycopg2 .我跟着psycopg2 I didn't understand everything as I am new to psycopg2.我不了解所有内容,因为我是 psycopg2 的新手。 Please, tell me how should I proceed with this.请告诉我我该怎么做。

def wait(conn):
    while True:
        state = conn.poll()
        if state == psycopg2.extensions.POLL_OK:
            break
        elif state == psycopg2.extensions.POLL_WRITE:
            select.select([], [conn.fileno()], [])
        elif state == psycopg2.extensions.POLL_READ:
            select.select([conn.fileno()], [], [])
        else:
            raise psycopg2.OperationalError("poll() returned %s" % state)

@app.route('/startListening', methods=['POST'])     
def listen():    
    conn = psycopg2.connect(dsn, async_=True)
    wait(conn)
    cur = conn.cursor()
    cur.execute("LISTEN db_notifications")
    wait(conn)
    print("Listening on db_notifications")
    while True: 
        conn.poll()
        while conn.notifies:
            notify = conn.notifies.pop()
            print(notify)
            handle_event(notify, conn)

def handle_event(noti,connec):
    data_from_notifications = noti.payload
    print(data_from_notifications)
    #some data processing
    #next cursor and query 
    acur = connec.cursor()
    acur.execute('')
    wait(connec)

The problem is the Timescaldb's action job scheduler.问题是 Timescaldb 的动作作业调度程序。 I moved to pgAgent job scheduler, and everything was working exactly how it's supposed to be.我搬到了 pgAgent 作业调度程序,一切都按照它应该的方式工作。

I think the problem is in the python code.我认为问题出在 python 代码中。 Could you try this, without the server context of your example?如果没有示例的服务器上下文,您可以试试这个吗?

conn = psycopg2.connect(dsn, async_=True)    
conn.set_isolation_level(psycopg2.extensions.ISOLATION_LEVEL_AUTOCOMMIT)    
cur = conn.cursor()
cur.execute("LISTEN db_notifications")
r, w, e = select.select([conn.fileno()], [], [], timeout)
conn.poll()
for n in conn.notifies:
    print(n.channel)
    print(n)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM