PostgreSQL рдЯрд╛рд╕реНрдХ рдХрддрд╛рд░

рд╣рд╛рдереА рдХреА рдХрддрд╛рд░ - pixabay.com


рдХрд╛рд░реНрдп рдкреНрд░рд╡рд╛рд╣ рдХреЗ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрддрд╛рд░реЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╡реЗ рдХрд▓рд╛рдХрд╛рд░реЛрдВ рдХреЗ рдмреАрдЪ рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд╕рдВрдЪрдп рдФрд░ рд╡рд┐рддрд░рдг рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИрдВред рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рд▓рд┐рдП рдХрддрд╛рд░реЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдЖрд╡рд╢реНрдпрдХрддрд╛рдПрдВ рднреА рдкреНрд░рджрд╛рди рдХрд░ рд╕рдХрддреА рд╣реИрдВ: рд╡рд┐рддрд░рдг рдЧрд╛рд░рдВрдЯреА, рдПрдХрдореБрд╢реНрдд рдЧрд╛рд░рдВрдЯреА, рдкреНрд░рд╛рдердорд┐рдХрддрд╛, рдЖрджрд┐ред


рдПрдХ рдирд┐рдпрдо рдХреЗ рд░реВрдк рдореЗрдВ, рддреИрдпрд╛рд░-рдХрд┐рдП рдЧрдП рд╕рдВрджреЗрд╢ рдХрддрд╛рд░рдмрджреНрдз рд╕рд┐рд╕реНрдЯрдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ (рдПрдордХреНрдпреВ - рд╕рдВрджреЗрд╢ рдХрддрд╛рд░), рд▓реЗрдХрд┐рди рдХрднреА-рдХрднреА рдЖрдкрдХреЛ рдПрдХ рддрджрд░реНрде рдХрддрд╛рд░ рдпрд╛ рдХреБрдЫ рд╡рд┐рд╢реЗрд╖ рдПрдХ (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдХрддрд╛рд░ рдФрд░ рдЕрдкрд╡рд╛рджреЛрдВ рдХреЗ рдХрд╛рд░рдг рд╕рдВрд╕рд╛рдзрд┐рдд рдирд╣реАрдВ рд╣реЛрдиреЗ рд╡рд╛рд▓реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рд╢реБрд░реВ рдХрд░рдиреЗ рдореЗрдВ рджреЗрд░реА) рдХреЛ рд╡реНрдпрд╡рд╕реНрдерд┐рдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред рдРрд╕реА рдХрддрд╛рд░реЛрдВ рдХреЗ рдирд┐рд░реНрдорд╛рдг рдкрд░ рдиреАрдЪреЗ рдЪрд░реНрдЪрд╛ рдХреА рдЬрд╛рдПрдЧреАред


рдкреНрд░рдпреЛрдЬреНрдпрддрд╛ рд╕реАрдорд╛рдПрдБ


рдкреНрд░рд╕реНрддрд╛рд╡рд┐рдд рд╕рдорд╛рдзрд╛рди рд╕рдорд╛рди рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдкреНрд░рд╡рд╛рд╣ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдП рдЧрдП рд╣реИрдВред рд╡реЗ рд╢рд┐рдерд┐рд▓ рдпреБрдЧреНрдорд┐рдд рдкреНрд░рдгрд╛рд▓реА рдФрд░ рдШрдЯрдХреЛрдВ рдХреЗ рдмреАрдЪ рдкрдм / рдЙрдк рдпрд╛ рд╕рдВрджреЗрд╢ рдХреЗ рдЖрдпреЛрдЬрди рдХреЗ рд▓рд┐рдП рдЙрдкрдпреБрдХреНрдд рдирд╣реАрдВ рд╣реИрдВред


рдПрдХ рд░рд┐рд▓реЗрд╢рдирд▓ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╢реАрд░реНрд╖ рдкрд░ рдПрдХ рдХрддрд╛рд░ рдЫреЛрдЯреЗ рдФрд░ рдордзреНрдпрдо рднрд╛рд░ (рдкреНрд░рддрд┐ рджрд┐рди рд╣рдЬрд╛рд░реЛрдВ рдХрд╛рд░реНрдпреЛрдВ, рджрд╕рд┐рдпреЛрдВ рд╕реЗ рд╕реИрдХрдбрд╝реЛрдВ рдХрд▓рд╛рдХрд╛рд░реЛрдВ) рдХреЗ рд▓рд┐рдП рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдХрд╛рдо рдХрд░рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдмрдбрд╝реЗ рдзрд╛рдЧреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╕рдорд╛рдзрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдмреЗрд╣рддрд░ рд╣реЛрддрд╛ рд╣реИред


рдкрд╛рдБрдЪ рд╢рдмреНрджреЛрдВ рдореЗрдВ рд╡рд┐рдзрд┐ рдХрд╛ рд╕рд╛рд░


select ... for update skip locked 

рдЖрдзрд╛рд░ рд░реЗрдЦрд╛


рд╕рд╛рджрдЧреА рдХреЗ рд▓рд┐рдП, рдЗрд╕рдХреЗ рдмрд╛рдж рдХреЗрд╡рд▓ рдЕрдирдиреНрдп рдХрд╛рд░реНрдп рдкрд╣рдЪрд╛рдирдХрд░реНрддрд╛рдУрдВ рдХреЛ рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рд╕рдВрдЧреНрд░рд╣реАрдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред рдХрд┐рд╕реА рддрд░рд╣ рдХрд╛ рдкреЗрд▓реЛрдб рдЬреЛрдбрд╝рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рдирд╣реАрдВ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред


рд╕рдмрд╕реЗ рд╕рд░рд▓ рдХрддрд╛рд░ рдХреЗ рд▓рд┐рдП рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рдХрд╛рд░реНрдп рдФрд░ рдЗрд╕рдХреА рд╕реНрдерд┐рддрд┐ рд╣реИ:


 create table task ( id bigint not null primary key, status integer not null default 0 -- 0 - , 1 -  , 2 -  ); create index task__status__idx on task (status); 

рдХрд╛рд░реНрдп рдЬреЛрдбрд╝рдирд╛:


 insert into task (id) values ($1) on conflict (id) do nothing; 

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:


 with next_task as ( select id from task where status = 0 limit 1 for update skip locked ) update task set status = 1 from next_task where task.id = next_task.id returning task.id; 

рдХрд╛рд░реНрдп рдкреВрд░реНрдгрддрд╛:


 update task set status = 2 where id = $1; 

рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдХрддрд╛рд░


рд╕рд░рд▓ рдорд╛рдорд▓реЗ рдореЗрдВ, рдХрд╛рд░реНрдп id рдЗрд╕рдХреА рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рд╣реИред рдХреЗрд╡рд▓ рдЕрдЧрд▓реЗ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдХреЛ рдмрджрд▓ рджрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ - рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдХрд╛рд░реНрдпреЛрдВ рдХреЗ рдЖрд╡рд╢реНрдпрдХ рдЖрджреЗрд╢ рдХреЗ рд╕рд╛рде order by id рдХреНрд░рдордмрджреНрдз рд╕реНрдерд┐рддрд┐ рдХреЛ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИред рдЖрдкрдХреЛ (status, id) рджреНрд╡рд╛рд░рд╛ рдПрдХ рд╕рдордЧреНрд░ рд╕реВрдЪрдХрд╛рдВрдХ рдмрдирд╛рдиреЗ рдХреА рднреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред


рдпрд╛, рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдХреЗ рд▓рд┐рдП, рдПрдХ рдЕрд▓рдЧ рдХреЙрд▓рдо рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ:


 create table task ( id bigint not null primary key, priority integer not null, status integer not null default 0 -- 0 - , 1 -  , 2 -  ); create index task__status__priority__idx on task (status, priority); 

рдХрд╛рд░реНрдп рдЬреЛрдбрд╝рдирд╛:
 insert into task (id, priority) values ($1, $2) on conflict (id) do nothing; 

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:
 with next_task as ( select id from task where status = 0 order by priority limit 1 for update skip locked ) update task set status = 1 from next_task where task.id = next_task.id returning task.id; 

рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдХреЙрд▓рдо рдЖрдкрдХреЛ рдлреНрд▓рд╛рдИ рдкрд░ рдХрд╛рд░реНрдп рдХреА рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдХреЛ рдмрджрд▓рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред


"рдЧрд┐рд░реЗ" рдХрд╛рд░реНрдпреЛрдВ рдХреА рдкреБрдирд░рд╛рд╡реГрддреНрддрд┐ рдХреЗ рд╕рд╛рде рдХрддрд╛рд░


рдХрд╛рд░реНрдп рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рджреМрд░рд╛рди рдХреЛрдИ рддреНрд░реБрдЯрд┐ рдпрд╛ рдЕрдкрд╡рд╛рдж рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдРрд╕реЗ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рдХрд╛рд░реНрдп рдХреЛ рдлрд┐рд░ рд╕реЗ рдХрддрд╛рд░рдмрджреНрдз рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдХрднреА-рдХрднреА рдХреБрдЫ рд╕рдордп рдХреЗ рд▓рд┐рдП рдЗрд╕рдХреЗ рджреЛрд╣рд░рд╛рдпрд╛ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд╕рдордп рдХреЛ рд╕реНрдердЧрд┐рдд рдХрд░рдирд╛ рдЕрднреА рднреА рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдпрджрд┐ рдЕрдкрд╡рд╛рдж рддреАрд╕рд░реЗ рдкрдХреНрд╖ рдХреА рд╕реЗрд╡рд╛ рдХреА рдЕрд╕реНрдерд╛рдпреА рдЕрдиреБрдкрд▓рдмреНрдзрддрд╛ рдХреЗ рдХрд╛рд░рдг рд╣реИред


 create table task ( id bigint not null primary key, status integer not null default 0, -- 0 - , 1 -  , 2 - , 3 - , 4 -   (  ) attempt integer not null default 0, delayed_to timestamp null, error_text text null ); create index task__status__delayed_to__idx on task (status, delayed_to); 

рдЬреИрд╕рд╛ рдХрд┐ рдЖрдк рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВ, рд╕реНрдерд┐рддрд┐рдпреЛрдВ рдХреА рд╕реВрдЪреА рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рд╣реБрдЖ рд╣реИ рдФрд░ рдирдП рдХреЙрд▓рдо рдЬреЛрдбрд╝реЗ рдЧрдП рд╣реИрдВ:


  • attempt - attempt рд╕рдВрдЦреНрдпрд╛; рдкреБрди: рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдирд┐рд░реНрдгрдп рд▓реЗрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рдкреНрд░рдпрд╛рд╕реЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХреЛ рд╕реАрдорд┐рдд рдХрд░реЗрдВ) рдФрд░ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ рдПрдХ рджреЗрд░реА рдХрд╛ рдЪрдпрди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП (рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдкреНрд░рддреНрдпреЗрдХ рдмрд╛рдж рдХреЗ рдкреНрд░рдпрд╛рд╕ рдореЗрдВ 10 * attempt рдорд┐рдирдЯ рддрдХ рджреЗрд░реА рд╣реЛ рд░рд╣реА рд╣реИ);
  • delayed_to - рдХрд╛рд░реНрдп рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрдЧрд▓реЗ рдкреНрд░рдпрд╛рд╕ рдХрд╛ рд╕рдордп;
  • error_text - рддреНрд░реБрдЯрд┐ рдкрд╛рдаред

рддреНрд░реБрдЯрд┐ рдкрд╛рда рдХреЛ рддреНрд░реБрдЯрд┐ рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рдореВрд╣ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред


рдПрдХ рдЙрджрд╛рд╣рд░рдг рд╣реИред рдирд┐рдЧрд░рд╛рдиреА рдкреНрд░рдгрд╛рд▓реА рд░рд┐рдкреЛрд░реНрдЯ рдХрд░рддреА рд╣реИ рдХрд┐ рд╕реНрдерд┐рддрд┐ "рддреНрд░реБрдЯрд┐" рдХреЗ рд╕рд╛рде рд╣рдЬрд╛рд░реЛрдВ рдХрд╛рд░реНрдп рдХрддрд╛рд░ рдореЗрдВ рдЬрдорд╛ рд╣реЛ рдЧрдП рд╣реИрдВред рд╣рдо рдЕрдиреБрд░реЛрдз рдкреВрд░рд╛ рдХрд░рддреЗ рд╣реИрдВ:


 select error_text, count(*) from task where status = 3 group by 1 order by 2 desc; 

рд╡рд┐рд╡рд░рдг рдХреЗ рд▓рд┐рдП, рдХрд▓рд╛рдХрд╛рд░реЛрдВ рдХреЗ рд▓реЙрдЧ рдкрд░ рдЬрд╛рдПрдВред рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдХреЛ рдареАрдХ рдХрд░реЗрдВ рдЬреЛ рддреНрд░реБрдЯрд┐ рдХрд╛ рдХрд╛рд░рдг рдмрдиреА (рдпрджрд┐ рд╕рдВрднрд╡ рд╣реЛ)ред рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рд╣рдо рд╕реНрдерд┐рддрд┐ рдХреЛ 0 рдкрд░ рд╕реЗрдЯ рдХрд░рдХреЗ рдпрд╛ рдЕрдЧрд▓реЗ рдкреНрд░рдпрд╛рд╕ рдХреЗ рд╕рдордп рдХреЛ рд╢рд┐рдлреНрдЯ рдХрд░рдХреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкреБрдирдГ рдЖрд░рдВрдн рдХрд░рддреЗ рд╣реИрдВред


рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдирдпрд╛ рдХрд╛рд░реНрдп рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:
 with next_task as ( select id from task where status = 0 limit 1 for update skip locked ) update task set status = 1, attempt = attempt + 1, delayed_to = null, error_text = null from next_task where task.id = next_task.id returning task.id; 

рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рдХрд╛рд░рдг рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рд▓рдВрдмрд┐рдд рд╣реИрдВ:
 with next_task as ( select id from task where status = 3 and delayed_to < localtimestamp limit 1 for update skip locked ) update task set status = 1, attempt = attempt + 1, delayed_to = null, error_text = null from next_task where task.id = next_task.id returning task.id; 

рдХрд╛рд░реНрдп рдХрд╛ рд╕рдлрд▓ рд╕рдорд╛рдкрди:
 update task set status = 2, delayed_to = null, error_text = null where id = $1; 

рдХрд╛рд░реНрдп рд╡рд┐рдлрд▓ рд╣реЛ рдЧрдпрд╛, рдорд┐рдирдЯреЛрдВ рдореЗрдВ (5 * рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ) рджреЛрд╣рд░рд╛рд╡ рд╣реЛрдЧрд╛:
 update task set status = 3, delayed_to = localtimestamp + make_interval(mins => 5 * attempt), error_text = $2 where id = $1; 

рдПрдХ рдШрд╛рддрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдкреВрд░рд╛ рд╣реБрдЖ рдХрд╛рд░реНрдп, рдХреЛрдИ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдирд╣реАрдВ рд╣реЛрдЧрд╛:
 update task set status = 4, delayed_to = null, error_text = $2 where id = $1; 

рдЕрдЧрд▓реЗ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдХреЛ рджреЛ рдореЗрдВ рд╡рд┐рднрд╛рдЬрд┐рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ рддрд╛рдХрд┐ DBMS рдкреНрд░рд╛рдердорд┐рдХрддрд╛ рдХрддрд╛рд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдкреНрд░рднрд╛рд╡реА рдХреНрд╡реЗрд░реА рдпреЛрдЬрдирд╛ рдмрдирд╛ рд╕рдХреЗред рдХреЗ рд╕рд╛рде рдЪрдпрди рдХреА рд╕реНрдерд┐рддрд┐ or рдХреНрд░рдордмрджреНрдзрддрд╛ рдХреЗ рд╕рд╛рде рдмрд╣реБрдд рдЧрд▓рдд рд╣реЛ рд╕рдХрддреА order by ред


рдореЗрдЯреНрд░рд┐рдХреНрд╕ рд╕рдВрдЧреНрд░рд╣


рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╡рд┐рд╢реЗрд╖рддрд╛рдПрдВ рдЬреЛрдбрд╝реЗрдВ:


  • рдХрд╛рд░реНрдп рдирд┐рд░реНрдорд╛рдг рд╕рдордп;
  • рдХрд╛рд░реНрдп рдкрд░рд┐рд╡рд░реНрддрди рд╕рдордп;
  • рдХрд╛рд░реНрдп рдХрд╛ рдкреНрд░рд╛рд░рдВрдн рдФрд░ рд╕рдорд╛рдкреНрддрд┐ рд╕рдордпред

 create table task ( id bigint not null primary key, status integer not null default 0, -- 0 - , 1 -  , 2 - , 3 - , 4 -   (  ) attempt integer not null default 0, begin_time timestamp null, end_time timestamp null, delayed_to timestamp null, error_text text null, created timestamp not null default localtimestamp, updated timestamp not null default localtimestamp ); create index task__status__delayed_to__idx on task (status, delayed_to); create index task__updated__idx on task (updated); 

рд╣рдо рд╕рднреА рдкреНрд░рд╢реНрдиреЛрдВ рдореЗрдВ рдЬреЛрдбрд╝реЗ рдЧрдП рдХреЙрд▓рдо рдкрд░ рд╡рд┐рдЪрд╛рд░ рдХрд░рддреЗ рд╣реИрдВред


рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдирдпрд╛ рдХрд╛рд░реНрдп рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:
 with next_task as ( select id from task where status = 0 limit 1 for update skip locked ) update task set status = 1, attempt = attempt + 1, begin_time = localtimestamp, end_time = null, delayed_to = null, error_text = null, updated = localtimestamp from next_task where task.id = next_task.id returning task.id; 

рдПрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рдХрд╛рд░рдг рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рд▓рдВрдмрд┐рдд рд╣реИрдВ:
 with next_task as ( select id from task where status = 3 and delayed_to < localtimestamp limit 1 for update skip locked ) update task set status = 1, attempt = attempt + 1, begin_time = localtimestamp, end_time = null, delayed_to = null, error_text = null, updated = localtimestamp from next_task where task.id = next_task.id returning task.id; 

рдХрд╛рд░реНрдп рдХрд╛ рд╕рдлрд▓ рд╕рдорд╛рдкрди:
 update task set status = 2, end_time = localtimestamp, delayed_to = null, error_text = null, updated = localtimestamp where id = $1; 

рдХрд╛рд░реНрдп рд╡рд┐рдлрд▓ рд╣реЛ рдЧрдпрд╛, рдорд┐рдирдЯреЛрдВ рдореЗрдВ (5 * рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ) рджреЛрд╣рд░рд╛рд╡ рд╣реЛрдЧрд╛:
 update task set status = 3, end_time = localtimestamp, delayed_to = localtimestamp + make_interval(mins => 5 * attempt), error_text = $2, updated = localtimestamp where id = $1; 

рдПрдХ рдШрд╛рддрдХ рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдкреВрд░рд╛ рд╣реБрдЖ рдХрд╛рд░реНрдп, рдХреЛрдИ рдкреБрдирдГ рдкреНрд░рдпрд╛рд╕ рдирд╣реАрдВ рд╣реЛрдЧрд╛:
 update task set status = 4, end_time = localtimestamp, delayed_to = null, error_text = $2, updated = localtimestamp where id = $1; 

рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреНрдпреЛрдВ рдкрдбрд╝ рд╕рдХрддреА рд╣реИ, рдЗрд╕рдХреЗ рдЙрджрд╛рд╣рд░рдг


рдЭреВрд▓рдиреЗ рд╡рд╛рд▓реЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдЦреЛрдЬреЗрдВ рдФрд░ рдкреБрдирдГ рдЖрд░рдВрдн рдХрд░реЗрдВ:


 update task set status = 3, end_time = localtimestamp, delayed_to = localtimestamp, error_text = 'hanged', updated = localtimestamp where status = 1 and updated < localtimestamp - interval '1 hour'; 

рдкреБрд░рд╛рдиреЗ рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рд╣рдЯрд╛рдирд╛:


 delete from task where updated < localtimestamp - interval '30 days'; 

рдХрд╛рд░реНрдп рдкреВрд░рд╛ рдХрд░рдиреЗ рдХреЗ рдЖрдБрдХрдбрд╝реЗ:


 select date_trunc('hour', end_time), count(*), sum(end_time - begin_time), avg(end_time - begin_time) from task where status = 2 and end_time >= '2019-12-16' group by 1 order by 1; 

рдкрд╣рд▓реЗ рд╕реЗ рдкреВрд░реНрдг рдХрд┐рдП рдЧрдП рдХрд╛рд░реНрдпреЛрдВ рдХреЛ рдкреБрдирдГ рдЖрд░рдВрдн рдХрд░реЗрдВ


рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдПрдХ рджрд╕реНрддрд╛рд╡реЗрдЬрд╝ рдЕрдкрдбреЗрдЯ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЖрдкрдХреЛ рдкреВрд░реНрдг-рдкрд╛рда рдЦреЛрдЬ рдХреЗ рд▓рд┐рдП рдЗрд╕реЗ рдлрд┐рд░ рд╕реЗ рд▓рд┐рдЦрдирд╛ рд╣реЛрдЧрд╛ред


 create table task ( id bigint not null primary key, task_updated_at timestamp not null default localtimstamp, status integer not null default 0, -- 0 - , 1 -  , 2 - , 3 - , 4 -   (  ) begin_time timestamp null, end_time timestamp null, delayed_to timestamp null, error_text text null, created timestamp not null default localtimestamp, updated timestamp not null default localtimestamp ); 

рдпрд╣рд╛рдВ, рдЯрд╛рд╕реНрдХ рдЕрдкрдбреЗрдЯ рд╕рдордп рдХреЗ рд▓рд┐рдП task_updated_at рдХреЙрд▓рдо рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди created рдлрд╝реАрд▓реНрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


рдХрд┐рд╕реА рдХрд╛рд░реНрдп рдХреЛ рдЬреЛрдбрд╝рдирд╛ рдпрд╛ рдЕрдкрдбреЗрдЯ рдХрд░рдирд╛ (рдкреБрдирдГ рдЖрд░рдВрдн рдХрд░рдирд╛):


 insert into task (id, task_updated_at) values ($1, $2) on conflict (id) do update set task_updated_at = excluded.task_updated_at, status = case when status = 1 then 1 else 0 end, delayed_to = null, error_text = null, updated = localtimestamp where task_updated_at < excluded.task_updated_at; 

рдпрд╣рд╛рдБ рдХреНрдпрд╛ рдЪрд▓ рд░рд╣рд╛ рд╣реИ рдпрджрд┐ рдпрд╣ рдЕрднреА рдкреВрд░рд╛ рдирд╣реАрдВ рд╣реЛ рд░рд╣рд╛ рд╣реИ рддреЛ рдПрдХ рдХрд╛рд░реНрдп "рдирдпрд╛" рд╣реЛ рдЬрд╛рддрд╛ рд╣реИред


рдХрд╛рд░реНрдп рдХреЛ рдкреВрд░рд╛ рдХрд░рдиреЗ рдХрд╛ рдЕрдиреБрд░реЛрдз рднреА рдЬрд╛рдВрдЪ рдХрд░реЗрдЧрд╛ рдХрд┐ рдХреНрдпрд╛ рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рджреМрд░рд╛рди рдЗрд╕реЗ рдмрджрд▓ рджрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред


рдЕрдЧрд▓реЗ рдХрд╛рд░реНрдп рдХреЗ рд▓рд┐рдП рдЕрдиреБрд░реЛрдз рдореЗрдЯреНрд░рд┐рдХреНрд╕ рдЗрдХрдЯреНрдард╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрддрд╛рд░ рдореЗрдВ рдЬреИрд╕реЗ рд╣реИрдВред


рдХрд╛рд░реНрдп рдХрд╛ рд╕рдлрд▓ рд╕рдорд╛рдкрди:


 update task set status = case when begin_time >= updated then 2 else 0 end, end_time = localtimestamp, delayed_to = null, error_text = null, updated = localtimestamp where id = $1; 

рддреНрд░реБрдЯрд┐ рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдп рдкреВрд░рд╛ рд╣реЛрдирд╛: рдХрд╛рд░реНрдп рдХреЗ рдЖрдзрд╛рд░ рдкрд░ред рдЖрдк рдкреБрдирд░рд╛рд░рдВрдн рдХрд░рдиреЗ рдореЗрдВ рдмрд┐рдирд╛ рд╢рд░реНрдд рджреЗрд░реА рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЖрдк рдЕрдкрдбреЗрдЯ рдХрд░рддреЗ рд╕рдордп рд╕реНрдерд┐рддрд┐ рдХреЛ "рдирдпрд╛" рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


рдкрд╛рдЗрдкрд▓рд╛рдЗрди


рдХрд╛рд░реНрдп рдХрдИ рдЪрд░рдгреЛрдВ рд╕реЗ рдЧреБрдЬрд░рддрд╛ рд╣реИред рдЖрдк рдкреНрд░рддреНрдпреЗрдХ рдЪрд░рдг рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрд▓рдЧ рдХрддрд╛рд░ рдмрдирд╛ рд╕рдХрддреЗ рд╣реИрдВред рдпрд╛ рдЖрдк рддрд╛рд▓рд┐рдХрд╛ рдореЗрдВ рд╕рдВрдмрдВрдзрд┐рдд рдХреЙрд▓рдо рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВред


рдореВрд▓ рдХрддрд╛рд░ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдПрдХ рдЙрджрд╛рд╣рд░рдг рддрд╛рдХрд┐ рдХреЛрдб рдХреЛ рдЕрд╡реНрдпрд╡рд╕реНрдерд┐рдд рди рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХреЗред рдкрд╣рд▓реЗ рд╕реЗ рд╡рд░реНрдгрд┐рдд рд╕рднреА рд╕рдВрд╢реЛрдзрдиреЛрдВ рдХреЛ рдмрд┐рдирд╛ рдХрд┐рд╕реА рд╕рдорд╕реНрдпрд╛ рдХреЗ рдЗрд╕ рдХрддрд╛рд░ рдореЗрдВ рд▓рд╛рдЧреВ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред


 create table task ( id bigint not null primary key, stage integer not null default 0, status integer not null default 0 ); create index task__stage__status__idx on task (stage, status); 

рджрд┐рдП рдЧрдП рдЪрд░рдг рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рдХрд░рдирд╛:


 with next_task as ( select id from task where stage = $1 and status = 0 limit 1 for update skip locked ) update task set status = 1 from next_task where task.id = next_task.id returning task.id; 

рд╕рдВрдХреЗрддрд┐рдд рдЪрд░рдг рдореЗрдВ рд╕рдВрдХреНрд░рдордг рдХреЗ рд╕рд╛рде рдХрд╛рд░реНрдп рдкреВрд░рд╛ рдХрд░рдирд╛:


 update task set stage = $2, status = 2 where id = $1; 

рдпрд╛ рдХреНрд░рдо рдореЗрдВ рдЕрдЧрд▓реЗ рдЪрд░рдг рдореЗрдВ рд╕рдВрдХреНрд░рдордг:


 update task set stage = stage + 1, status = 2 where id = $1; 

рдЕрдиреБрд╕реВрдЪрд┐рдд рдХрд╛рд░реНрдп


рдпрд╣ рджреЛрд╣рд░рд╛рдиреЗ рдХреА рдХрддрд╛рд░ рдХрд╛ рдПрдХ рд░реВрдкрд╛рдВрддрд░ рд╣реИред


рдкреНрд░рддреНрдпреЗрдХ рдХрд╛рд░реНрдп рдХрд╛ рдЕрдкрдирд╛ рдХрд╛рд░реНрдпрдХреНрд░рдо рд╣реЛ рд╕рдХрддрд╛ рд╣реИ (рд╕рд░рд▓рддрдо рд╕рдВрд╕реНрдХрд░рдг рдореЗрдВ, рд▓реЙрдиреНрдЪ рдХреА рдЖрд╡реГрддреНрддрд┐)ред


 create table task ( id bigint not null primary key, period integer not null, --     status integer not null default 0, -- 0 - , 1 -   next_run_time timestamp not null default localtimestamp ); create index task__status__next_run_time__idx on task (status, next_run_time); 

рдХрд╛рд░реНрдп рдЬреЛрдбрд╝рдирд╛:


 insert into task (id, period, next_run_time) values ($1, $2, $3); 

рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХрд╛рд░реНрдп рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛:


 with next_task as ( select id from task where status = 0 and next_run_time <= localtimestamp limit 1 for update skip locked ) update task set status = 1 from next_task where task.id = next_task.id returning task.id; 

рдХрд╛рд░реНрдп рдХреЛ рдкреВрд░рд╛ рдХрд░рдирд╛ рдФрд░ рдЕрдЧрд▓реЗ рд░рди рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рдирд╛:


 update task set status = 0, next_run_time = next_run_time + make_interval(secs => period) where id = $1 

рдПрдХ рдирд┐рд╖реНрдХрд░реНрд╖ рдХреЗ рдмрдЬрд╛рдп


RDBMS рдЯреВрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рд╡рд┐рд╢реЗрд╖ рдХрд╛рд░реНрдп рдХрддрд╛рд░ рдмрдирд╛рдиреЗ рдореЗрдВ рдХреБрдЫ рднреА рдЬрдЯрд┐рд▓ рдирд╣реАрдВ рд╣реИред


"рд╕реНрд╡-рдирд┐рд░реНрдорд┐рдд" рдХрддрд╛рд░ рдЬрд╡рд╛рдм рджреЗрдЧреА рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рд╕рдмрд╕реЗ рдЬрдВрдЧрд▓реА рд╡рд╕реНрддреБрддрдГ рдХрд┐рд╕реА рднреА рд╡реНрдпрд╡рд╕рд╛рдп / рдбреЛрдореЗрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ред


рдЦреИрд░, рд╣рдореЗрдВ рдпрд╣ рдирд╣реАрдВ рднреВрд▓рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рдХрд┐рд╕реА рднреА рдЕрдиреНрдп рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рддрд░рд╣, рдХрддрд╛рд░ рдореЗрдВ рд╕рд░реНрд╡рд░, рдХреНрд╡реЗрд░реА рдФрд░ рдЗрдВрдбреЗрдХреНрд╕ рдХреА рд╡рд┐рдЪрд╛рд░рд╢реАрд▓ рдЯреНрдпреВрдирд┐рдВрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИред

Source: https://habr.com/ru/post/hi481556/


All Articles