Package: geeteventbus
An eventbus for concurrent programminggeeteventbus is a library that allows publish-subscribe-style communication. There is no need for the components to register to each-other. It is inspired by a Java library, Guava eventbus from Google. But it is not exactly same as the Guava eventbus library.geeteventbus simplifies handling events from publishers and subscribers.publisher and subscribers don’t need to create threads to concurrently process the events.the eventbus can be synchronus, where the events are delivered from the same thread posting the eventsevents can be delivered to subscibers in the same order they are postedsubscribers may be declared as thread-safe, in that case same subscriber may be invoked concurrently for processing multiple eventsevents for which there are no subscribers are registered yet are simply discared by the eventbus.the eventbus is not to be used for inter process communication. Publishers and subsribers must run on the same processBasic workingWe create an eventbusfromgeeteventbus.eventbusimporteventbuseb=eventbus()This will create an eventbus with the defaults. The default eventbus will have below characteristics:the maximum queued event limit is set to 10000number of executor thread is 8the subscribers will be called asynchronouslysubscibers are treated as thread-safe and hence same subscribers may be invoked simultaneously  on different threadsCreate a subsclass of subscriber and override the process method. Create an object of this class and register it to the eventbus for receiving messages with certain topics:fromgeeteventbus.subscriberimportsubscriberfromgeeteventbus.eventbusimporteventbusfromgeeteventbus.eventimporteventclassmysubscriber(subscriber):defprocess(self,eventobj):ifnotisinstance(eventobj,event):print('Invalid object type is passed.')returntopic=eventobj.get_topic()data=eventobj.get_data()print('Processing event with TOPIC:%s, DATA:%s'%(topic,data))subscr=mysubscriber()eb.register_consumer(subscr,'an_important_topic')Post some events to the eventbus with the topic “an_important_topic”.fromgeeteventbus.eventimporteventeobj1=('an_important_topic','This is some data for the event 1')eobj2=('an_important_topic','This is some data for the event 2')eobj3=('an_important_topic','This is some data for the event 3')eobj3=('an_important_topic','This is some data for the event 4')eb.post(eobj1)eb.post(eobj2)eb.post(eobj3)eb.post(eobj4)We may gracefully shutdown the eventbus before exiting the processeb.shutdown()The complete example is below:fromtimeimportsleepfromgeeteventbus.subscriberimportsubscriberfromgeeteventbus.eventbusimporteventbusfromgeeteventbus.eventimporteventclassmysubscriber(subscriber):defprocess(self,eventobj):ifnotisinstance(eventobj,event):print('Invalid object type is passed.')returntopic=eventobj.get_topic()data=eventobj.get_data()print('Processing event with TOPIC:%s, DATA:%s'%(topic,data))eb=eventbus()subscr=mysubscriber()eb.register_consumer(subscr,'an_important_topic')eobj1=event('an_important_topic','This is some data for the event 1')eobj2=event('an_important_topic','This is some data for the event 2')eobj3=event('an_important_topic','This is some data for the event 3')eobj4=event('an_important_topic','This is some data for the event 4')eb.post(eobj1)eb.post(eobj2)eb.post(eobj3)eb.post(eobj4)eb.shutdown()sleep(2)A more detailed example is given below. A subscriber (counter_aggregator) aggregates the values for
a set of counters. It registers itself to an eventbus for receiving events for the
counters(topics). A set of producers update the values for the counters and post events describing
the counter to the eventbus:fromthreadingimportLock,Threadfromtimeimportsleep,timefromgeeteventbus.eventbusimporteventbusfromgeeteventbus.eventimporteventfromgeeteventbus.subscriberimportsubscriberfromrandomimportrandintclasscounter_aggregator(subscriber,Thread):'''
    Aggregator for a set of counters. Multiple threads updates the counts which
    are aggregated by this class and output the aggregated value periodically.
    '''def__init__(self,counter_names):Thread.__init__(self)self.counter_names=counter_namesself.locks={}self.counts={}self.keep_running=Trueself.collect_times={}forcounterincounter_names:self.locks[counter]=Lock()self.counts[counter]=0self.collect_times[counter]=time()defprocess(self,eobj):'''
        Process method calls with the event object eobj. eobj has the counter name as the topic
        and an int count as the value for the counter.
        '''counter_name=eobj.get_topic()ifcounter_namenotinself.counter_names:returncount=eobj.get_data()withself.locks[counter_name]:self.counts[counter_name]+=countdefstop(self):self.keep_running=Falsedef__call__(self):'''
        Keep outputing the aggregated counts every 2 seconds
        '''whileself.keep_running:sleep(2)forcounter_nameinself.counter_names:withself.locks[counter_name]:print('Change for counter%s=%d, in last%fsecs'%(counter_name,self.counts[counter_name],time()-self.collect_times[counter_name]))self.counts[counter_name]=0self.collect_times[counter_name]=time()print('Aggregator exited')classcount_producer:'''
    Producer for counters. Every 0.02 seconds post the "updated" value for a
    counter randomly
    '''def__init__(self,counters,ebus):self.counters=countersself.ebus=ebusself.keep_running=Trueself.num_counter=len(counters)defstop(self):self.keep_running=Falsedef__call__(self):whileself.keep_running:ev=event(self.counters[randint(0,self.num_counter-1)],randint(1,100))ebus.post(ev)sleep(0.02)print('producer exited')if__name__=='__main__':ebus=eventbus()counters=['c1','c2','c3','c4']subcr=counter_aggregator(counters)producer=count_producer(counters,ebus)forcounterincounters:ebus.register_consumer(subcr,counter)threads=[]i=30whilei>0:threads.append(Thread(target=producer))i-=1aggregator_thread=Thread(target=subcr)aggregator_thread.start()forthrdinthreads:thrd.start()sleep(20)producer.stop()subcr.stop()sleep(2)ebus.shutdown()