到目前为止,我所做的是一个使用节流ID和时间间隔并在给定时间间隔多次调用的情况下返回true
的函数。否则,它将返回null
。
这在测试时按预期工作,但在更强大的工作负载中会产生错误,
ERROR: canceling statement due to statement timeout
===> - CONTEXT: while locking tuple (2,108) in relation "shared"
SQL function "throttle" statement 1
任何建议如何避免死锁?
CREATE OR REPLACE FUNCTION monitor.throttle(id_i text, every_i interval)
RETURNS boolean
LANGUAGE sql
AS $function$
with
nv as (
select id_i id,
'1'::text val,
every_i every,
clock_timestamp() modtime
),
upsert as (
update monitor.shared m set
modtime = case
when m.modtime+every >nv.modtime then m.modtime
else nv.modtime
end
FROM nv
WHERE m.id = nv.id
RETURNING m.*
),
ins as (
INSERT INTO monitor.shared (id,modtime,val)
SELECT id,modtime,val FROM nv
WHERE NOT EXISTS (
SELECT 1 FROM upsert up WHERE up.id = nv.id
)
returning *
)
select
case
-- don't throttle
when i.id is not null or u.modtime=nv.modtime then null
-- throttle
else true
end
from nv
left join upsert u on true
left join ins i on true
$function$
\d monitor.shared
Unlogged table "monitor.shared"
Column | Type | Modifiers
---------+--------------------------+------------------------
id | text | not null
val | text |
modtime | timestamp with time zone | not null default now()
Indexes:
"shared_pkey" PRIMARY KEY, btree (id)