X-Original-To: pgsql-sql-postgresql.org@localhost.postgresql.org Received: from localhost (unknown [200.46.204.144]) by svr1.postgresql.org (Postfix) with ESMTP id E1FA83A5D04 for ; Wed, 12 Jan 2005 16:19:00 +0000 (GMT) Received: from svr1.postgresql.org ([200.46.204.71]) by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024) with ESMTP id 37380-04 for ; Wed, 12 Jan 2005 16:18:48 +0000 (GMT) Received: from mail.libertyrms.com (unknown [207.219.45.62]) by svr1.postgresql.org (Postfix) with ESMTP id ADB073A5CE6 for ; Wed, 12 Jan 2005 16:18:47 +0000 (GMT) Received: from dba4.int.libertyrms.com ([10.1.3.13] ident=ahammond) by mail.libertyrms.com with esmtp (Exim 4.22) id 1ColCn-00089d-GS; Wed, 12 Jan 2005 11:18:45 -0500 Message-ID: <41E54DE5.9000505@ca.afilias.info> Date: Wed, 12 Jan 2005 11:18:45 -0500 From: Andrew Hammond Organization: Afilias Canada Corp. User-Agent: Mozilla Thunderbird 0.9 (X11/20041124) X-Accept-Language: en-us, en MIME-Version: 1.0 To: =?ISO-8859-1?Q?K=D6PFERL_Robert?= Cc: "'pgsql-sql@postgresql.org'" Subject: Re: Implementing queue semantics (novice) References: In-Reply-To: X-Enigmail-Version: 0.89.0.0 X-Enigmail-Supports: pgp-inline, pgp-mime Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 8bit X-SA-Exim-Mail-From: ahammond@ca.afilias.info X-SA-Exim-Scanned: No; SAEximRunCond expanded to false X-Virus-Scanned: by amavisd-new at hub.org X-Spam-Status: No, hits=0.521 tagged_above=0 required=5 tests=AWL, FORGED_RCVD_HELO, INFO_TLD X-Spam-Level: X-Archive-Number: 200501/53 X-Sequence-Number: 19841 -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 The name for what you're looking to build is a concurrent batch processing system. Here's a basic one. - -- adding processes BEGIN; INSERT INTO queue (queue_id, processing_pid, processing_start, ~ processing_status, foreign_id) VALUES (DEFAULT, NULL, NULL, ~ (SELECT queue_status_id FROM queue_status WHERE name = 'pending'), ~ foreign_id); COMMIT; - -- removing processes BEGIN; SELECT queue_id, foreign_id FROM queue WHERE processing_status = (SELECT queue_status_id FROM queue_status ~ WHERE name = 'pending') ORDER BY queue_id LIMIT 1 FOR UPDATE; UPDATE queue SET processing_pid = ?, ~ processing_start = now(), ~ processing_status = (SELECT queue_status_id FROM queue_status WHERE ~ name = 'active') WHERE id = ?; COMMIT; - -- client code does whatever it's going to do here BEGIN; SELECT 1 FROM queue WHERE queue_id = ? AND processing_pid = ? FOR UPDATE; - -- confirm that it exists DELETE FROM queue WHERE queue_id = ? INSERT INTO queue_history (queue_id, processing_pid, processing_start, ~ processing_complete, processing_status, foreign_id) VALUES (queue_id, processing_pid, processing_start, now(), ~ (SELECT queue_status_id FROM queue_status WHERE name = 'done'), ~ foreign_id); COMMIT; - -- a seperate process reaps orphaned entries should processing fail. BEGIN; SELECT queue_id, processing_pid FROM queue WHERE now() - processing_start > 'some reasonable interval'::interval AND processing_status = (SELECT queue_status_id FROM queue_status WHERE ~ name = 'active' FOR UPDATE; - -- for each entry, check to see if the PID is still running UPDATE queue SET ~ processing_pid = NULL, ~ processing_start = NULL, ~ processing_status = (SELECT id FROM queue_status WHERE name = 'pending') WHERE id = ?; COMMIT; There are more complicated approaches available. If you plan to have multiple machines processing, you probably want to add a processing_node entry too. KÖPFERL Robert wrote: | Hi, | | since I am new to writing stored procedures I'd like to ask first bevore I | do a mistake. | | I want to implement some kind of queue (fifo). There are n users/processes | that add new records to a table and there are m consumers that take out | these records and process them. | It's however possible for a consumer to die or loose connection while | records must not be unprocessed. They may rather be processed twice. | | This seems to me as a rather common problem. But also with atomicy-holes to | fall into. | How is this commonly implemented? | | | I can imagine an 'add' and a 'get' function together with one aditional | 'processed' timestamp-column? | | | | Thanks for helping me do the right. | | ---------------------------(end of broadcast)--------------------------- | TIP 4: Don't 'kill -9' the postmaster - -- Andrew Hammond 416-673-4138 ahammond@ca.afilias.info Database Administrator, Afilias Canada Corp. CB83 2838 4B67 D40F D086 3568 81FC E7E5 27AF 4A9A -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.2.5 (GNU/Linux) iD8DBQFB5U3kgfzn5SevSpoRAoesAKCAZkr61I5knCw9tIr8rlO0xri7YACgifrn N01nXZY8UKmIlTnGkngHKUo= =UXRk -----END PGP SIGNATURE-----