diff --git a/conf/trigger.cfg.example b/conf/trigger.cfg.example
--- a/conf/trigger.cfg.example
+++ b/conf/trigger.cfg.example
@@ -13,3 +13,4 @@
 blacklist_releases = el5,el6
 job_logging = False
 joblog_file = /var/log/taskotron-trigger/jobs.csv
+fuse_delay = 1000 ; seconds
diff --git a/jobtriggers/__init__.py b/jobtriggers/__init__.py
--- a/jobtriggers/__init__.py
+++ b/jobtriggers/__init__.py
@@ -0,0 +1,23 @@
+import fedmsg.consumers
+
+from . import config, triggers, utils
+
+class JobTrigger(fedmsg.consumers.FedmsgConsumer):
+    def __init__(self, *args, **kw):
+        super(JobTrigger, self).__init__(*args, **kw)
+        self.trigger = triggers.get_trigger(config.trigger_type)
+
+    def trigger_tasks(self, item, item_type, tasks, arches):
+        for task in tasks:
+            for arch in arches:
+                self.log.info('triggering %s for %s on %s', task, item, arch)
+
+                if config.job_logging:
+                    try:
+                        utils.log_job(config.joblog_file, item, item_type, task, arch)
+                    except IOError, e:
+                        self.log.warning('Cannot log a job into %s', config.joblog_file)
+
+                output = self.trigger.trigger_job(item, item_type, task, arch)
+                for line in output:
+                    self.log.info(line)
diff --git a/jobtriggers/bodhi_msg.py b/jobtriggers/bodhi_msg.py
--- a/jobtriggers/bodhi_msg.py
+++ b/jobtriggers/bodhi_msg.py
@@ -1,18 +1,37 @@
 import fedmsg
 import fedmsg.encoding
-import fedmsg.consumers
+import moksha.hub.reactor
 
-from . import triggers, utils, config
+from twisted.internet.task import LoopingCall
 
+from . import utils, config
+from . import JobTrigger
 
-class BodhiJobTrigger(fedmsg.consumers.FedmsgConsumer):
+class BodhiJobTrigger(JobTrigger):
     topic = "org.fedoraproject.prod.bodhi.update.request.*"
     jsonify = False
     config_key = 'taskotron.bodhijobtrigger.enabled'
 
     def __init__(self, *args, **kw):
         super(BodhiJobTrigger, self).__init__(*args, **kw)
-        self.trigger = triggers.get_trigger(config.trigger_type)
+
+        self.queued_tags = set()
+        self.queued_arches = set()
+
+        # check for bodhi_to_koji_tags tasks queue every config.fuse_delay seconds
+        lc = LoopingCall(self.delayed_consume)
+        lc.start(config.fuse_delay)
+
+    def delayed_consume(self):
+        if self.queued_tags:
+            try:
+                for tag in self.queued_tags:
+                    self.trigger_tasks(tag, 'koji_tag', config.bodhi_to_koji_tag_tasks, self.queued_arches)
+            finally:
+                self.queued_tags = set()
+                self.queued_arches = set()
+        else:
+            self.log.debug("Woke up, but there were no messages.")
 
     def consume(self, message):
         usable_message = fedmsg.encoding.loads(message.body)
@@ -38,20 +57,10 @@
 
         arches = utils.get_arches(nvr=nvrs[0])
 
-        tasks = []
-        tasks += [(updatetitle, 'bodhi_id', task) for task in config.bodhi_tasks]
-        tasks += [(koji_tag, 'koji_tag', task) for task in config.bodhi_to_koji_tag_tasks]
-
-        for (item, item_type, task) in tasks:
-            for arch in arches:
-                self.log.info('triggering %s for %s on %s', task, item, arch)
-
-                if config.job_logging:
-                    try:
-                        utils.log_job(config.joblog_file, item, item_type, task, arch)
-                    except IOError, e:
-                        self.log.warning('Cannot log a job into %s', config.joblog_file)
+        self.log.info('setting fuse (%d seconds) for koji_tag %s', config.fuse_delay, koji_tag)
+        self.queued_tags.add(koji_tag)
+        for arch in arches:
+            self.queued_arches.add(arch)
 
-                output = self.trigger.trigger_job(item, item_type, task, arch)
-                for line in output:
-                    self.log.info(line)
+        # run bodhi_id tasks for every update
+        self.trigger_tasks(updatetitle, 'bodhi_id', config.bodhi_tasks, arches)
diff --git a/jobtriggers/config.py b/jobtriggers/config.py
--- a/jobtriggers/config.py
+++ b/jobtriggers/config.py
@@ -17,6 +17,7 @@
 blacklist_releases = el5,el6
 job_logging = False
 joblog_file = /var/log/taskotron-trigger/jobs.cvs
+fuse_delay = 1000 ; seconds
 """
 
 config = ConfigParser.ConfigParser()
@@ -37,3 +38,4 @@
 blacklist_releases = [e.strip() for e in config.get('trigger', 'blacklist_releases').split(',')]
 job_logging = True if config.get('trigger', 'job_logging') == 'True' else False
 joblog_file = config.get('trigger', 'joblog_file')
+fuse_delay = int(config.get('trigger', 'fuse_delay')) # seconds
diff --git a/jobtriggers/koji_msg.py b/jobtriggers/koji_msg.py
--- a/jobtriggers/koji_msg.py
+++ b/jobtriggers/koji_msg.py
@@ -1,20 +1,18 @@
 import fedmsg
 import fedmsg.encoding
-import fedmsg.consumers
-
-from . import triggers, utils, config
 
+from . import utils, config
+from . import JobTrigger
 
 ITEM_TYPE = 'koji_build'
 
-class KojiJobTrigger(fedmsg.consumers.FedmsgConsumer):
+class KojiJobTrigger(JobTrigger):
     topic = "org.fedoraproject.prod.buildsys.tag"
     jsonify = False
     config_key = 'taskotron.kojijobtrigger.enabled'
 
     def __init__(self, *args, **kw):
         super(KojiJobTrigger, self).__init__(*args, **kw)
-        self.trigger = triggers.get_trigger(config.trigger_type)
 
     def consume(self, message):
         usable_message = fedmsg.encoding.loads(message.body)
@@ -38,16 +36,4 @@
 
         arches = utils.get_arches(buildid=buildid)
 
-        for task in config.koji_tasks:
-            for arch in arches:
-                self.log.info('triggering %s for %s on %s', task, envr, arch)
-
-                if config.job_logging:
-                    try:
-                        utils.log_job(config.joblog_file, envr, ITEM_TYPE, task, arch)
-                    except IOError, e:
-                        self.log.warning('Cannot log a job into %s', config.joblog_file)
-
-                output = self.trigger.trigger_job(envr, ITEM_TYPE, task, arch)
-                for line in output:
-                    self.log.info(line)
+        self.trigger_tasks(envr, ITEM_TYPE, config.koji_tasks, arches)
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -14,7 +14,7 @@
 
 setup(
     name='jobtriggers',
-    version='0.3.0',
+    version='0.3.1',
     description='triggering jobs via fedmsg',
     author='Tim Flink',
     author_email='tflink@fedoraproject.org',
diff --git a/taskotron-trigger.spec b/taskotron-trigger.spec
--- a/taskotron-trigger.spec
+++ b/taskotron-trigger.spec
@@ -1,5 +1,5 @@
 Name:           taskotron-trigger
-Version:        0.3.0
+Version:        0.3.1
 Release:        1%{?dist}
 Summary:        Triggering Taskotron jobs via fedmsg.
 
@@ -13,6 +13,7 @@
 Requires:       koji
 Requires:       python-bunch
 Requires:       python-requests
+Requires:       python-twisted
 Requires:       fedmsg
 Requires:       fedmsg-hub
 
@@ -60,7 +61,10 @@
 
 
 %changelog
-* Mon Jun 16 2014 Tim Flink <tflink@fedoraproject.org> - 0.2.1-1
+* Mon Jun 23 2014 Martin Krizek <mkrizek@redhat.com> - 0.3.1-1
+- add python-twisted as dep
+
+* Mon Jun 16 2014 Tim Flink <tflink@fedoraproject.org> - 0.3.0-1
 - releasing 0.3.0
 
 * Fri Jun 13 2014 Tim Flink <tflink@fedoraproject.org> - 0.2.1-1
diff --git a/testing/test_bodhi_trigger.py b/testing/test_bodhi_trigger.py
--- a/testing/test_bodhi_trigger.py
+++ b/testing/test_bodhi_trigger.py
@@ -48,16 +48,20 @@
 
         trigger_calls = self.helper.trigger.trigger_job.calls()
 
-        assert len(trigger_calls) == 8
+        assert len(trigger_calls) == 4
 
         assert trigger_calls[0][1] == (self.ref_updatetitle, 'bodhi_id', self.ref_tasks[0], self.ref_validarches[0])
         assert trigger_calls[1][1] == (self.ref_updatetitle, 'bodhi_id', self.ref_tasks[0], self.ref_validarches[1])
         assert trigger_calls[2][1] == (self.ref_updatetitle, 'bodhi_id', self.ref_tasks[1], self.ref_validarches[0])
         assert trigger_calls[3][1] == (self.ref_updatetitle, 'bodhi_id', self.ref_tasks[1], self.ref_validarches[1])
-        assert trigger_calls[4][1] == (self.ref_koji_tag, 'koji_tag', self.ref_tasks[0], self.ref_validarches[0])
-        assert trigger_calls[5][1] == (self.ref_koji_tag, 'koji_tag', self.ref_tasks[0], self.ref_validarches[1])
-        assert trigger_calls[6][1] == (self.ref_koji_tag, 'koji_tag', self.ref_tasks[1], self.ref_validarches[0])
-        assert trigger_calls[7][1] == (self.ref_koji_tag, 'koji_tag', self.ref_tasks[1], self.ref_validarches[1])
+
+    def test_consume_delayed_queues(self):
+        self.helper.consume(self.ref_message)
+
+        trigger_calls = self.helper.trigger.trigger_job.calls()
+
+        assert self.helper.queued_tags == set([self.ref_koji_tag])
+        assert self.helper.queued_arches == set(self.ref_validarches)
 
     def test_consume_notwatched_topic(self):
         ref_topic = 'org.fedoraproject.pro.bodhi.update.request.randomtopic'
@@ -85,6 +89,22 @@
 
         self.helper.consume(self.ref_message)
 
+        assert self.ref_koji_tag + '-testing' in self.helper.queued_tags
+
+    def test_delayed_consume(self):
+        self.helper.queued_tags = [self.ref_koji_tag]
+        self.helper.queued_arches = self.ref_validarches
+
+        self.helper.delayed_consume()
+
         trigger_calls = self.helper.trigger.trigger_job.calls()
 
-        assert trigger_calls[4][1][0] == self.ref_koji_tag + '-testing'
+        assert len(trigger_calls) == 4
+
+        assert trigger_calls[0][1] == (self.ref_koji_tag, 'koji_tag', self.ref_tasks[0], self.ref_validarches[0])
+        assert trigger_calls[1][1] == (self.ref_koji_tag, 'koji_tag', self.ref_tasks[0], self.ref_validarches[1])
+        assert trigger_calls[2][1] == (self.ref_koji_tag, 'koji_tag', self.ref_tasks[1], self.ref_validarches[0])
+        assert trigger_calls[3][1] == (self.ref_koji_tag, 'koji_tag', self.ref_tasks[1], self.ref_validarches[1])
+
+        assert self.helper.queued_tags == set()
+        assert self.helper.queued_arches == set()

