Event-driven architecture

Last updated

Event-driven architecture (EDA) is a software architecture paradigm concerning the production and detection of events.

Contents

Overview

An event can be defined as "a significant change in state". [1] For example, when a consumer purchases a car, the car's state changes from "for sale" to "sold". A car dealer's system architecture may treat this state change as an event whose occurrence can be made known to other applications within the architecture. From a formal perspective, what is produced, published, propagated, detected or consumed is a (typically asynchronous) message called the event notification, and not the event itself, which is the state change that triggered the message emission. Events do not travel, they just occur. However, the term event is often used metonymically to denote the notification message itself, which may lead to some confusion. This is due to Event-driven architectures often being designed atop message-driven architectures, where such communication pattern requires one of the inputs to be text-only, the message, to differentiate how each communication should be handled.

This architectural pattern may be applied by the design and implementation of applications and systems that transmit events among loosely coupled software components and services. An event-driven system typically consists of event emitters (or agents), event consumers (or sinks), and event channels. Emitters have the responsibility to detect, gather, and transfer events. An Event Emitter does not know the consumers of the event, it does not even know if a consumer exists, and in case it exists, it does not know how the event is used or further processed. Sinks have the responsibility of applying a reaction as soon as an event is presented. The reaction might or might not be completely provided by the sink itself. For instance, the sink might just have the responsibility to filter, transform and forward the event to another component or it might provide a self-contained reaction to such an event. Event channels are conduits in which events are transmitted from event emitters to event consumers. The knowledge of the correct distribution of events is exclusively present within the event channel.[ citation needed ] The physical implementation of event channels can be based on traditional components such as message-oriented middleware or point-to-point communication which might require a more appropriate transactional executive framework[ clarify ].

Building systems around an event-driven architecture simplifies horizontal scalability in distributed computing models and makes them more resilient to failure. This is because application state can be copied across multiple parallel snapshots for high-availability. [2] New events can be initiated anywhere, but more importantly propagate across the network of data stores updating each as they arrive. Adding extra nodes becomes trivial as well: you can simply take a copy of the application state, feed it a stream of events and run with it. [3]

Event-driven architecture can complement service-oriented architecture (SOA) because services can be activated by triggers fired on incoming events. [4] [5] This paradigm is particularly useful whenever the sink does not provide any self-contained executive[ clarify ].

SOA 2.0 evolves the implications SOA and EDA architectures provide to a richer, more robust level by leveraging previously unknown causal relationships to form a new event pattern.[ vague ] This new business intelligence pattern triggers further autonomous human or automated processing that adds exponential value to the enterprise by injecting value-added information into the recognized pattern which could not have been achieved previously.[ vague ]

Topologies

Event driven architecture has two primary topologies: “broker topology” wherein components broadcast events to the entire system without any orchestrator. It provides the highest performance and scalability. Whereas in “mediator topology” there is a central orchestrator which controls workflow of events. It provides better control and error handling capabilities. You can also use a hybrid model and combine these two topologies. [6]

Event structure

An event can be made of two parts, the event header and the event body. The event header might include information such as event name, time stamp for the event, and type of event. The event body provides the details of the state change detected. An event body should not be confused with the pattern or the logic that may be applied in reaction to the occurrence of the event itself.

Event flow layers

An event driven architecture may be built on four logical layers, starting with the sensing of an event (i.e., a significant temporal state or fact), proceeding to the creation of its technical representation in the form of an event structure and ending with a non-empty set of reactions to that event. [7]

Event Producer

The first logical layer is the event producer, which senses a fact and represents that fact as an event message. As an example, an event producer could be an email client, an E-commerce system, a monitoring agent or some type of physical sensor.

Converting the data collected from such a diverse set of data sources to a single standardized form of data for evaluation is a significant task in the design and implementation of this first logical layer. [7] However, considering that an event is a strongly declarative frame, any informational operations can be easily applied, thus eliminating the need for a high level of standardization.[ citation needed ]

Event channel

This is the second logical layer. An event channel is a mechanism of propagating the information collected from an event generator to the event engine [7] or sink. This could be a TCP/IP connection, or any type of an input file (flat, XML format, e-mail, etc.). Several event channels can be opened at the same time. Usually, because the event processing engine has to process them in near real time, the event channels will be read asynchronously. The events are stored in a queue, waiting to be processed later by the event processing engine.

Event processing engine

The event processing engine is the logical layer responsible for identifying an event, and then selecting and executing the appropriate reaction. It can also trigger a number of assertions. For example, if the event that comes into the event processing engine is a product ID low in stock, this may trigger reactions such as “Order product ID” and “Notify personnel”. [7]

Downstream event-driven activity

This is the logical layer where the consequences of the event are shown. This can be done in many different ways and forms; e.g., an email is sent to someone and an application may display some kind of warning on the screen. [7] Depending on the level of automation provided by the sink (event processing engine) the downstream activity might not be required.

Event processing styles

There are three general styles of event processing: simple, stream, and complex. The three styles are often used together in a mature event-driven architecture. [7]

Simple event processing

Simple event processing concerns events that are directly related to specific, measurable changes of condition. In simple event processing, a notable event happens which initiates downstream action(s). Simple event processing is commonly used to drive the real-time flow of work, thereby reducing lag time and cost. [7]

For example, simple events can be created by a sensor detecting changes in tire pressures or ambient temperature. The car's tire incorrect pressure will generate a simple event from the sensor that will trigger a yellow light advising the driver about the state of a tire.

Event stream processing

In event stream processing (ESP), both ordinary and notable events happen. Ordinary events (orders, RFID transmissions) are screened for notability and streamed to information subscribers. Event stream processing is commonly used to drive the real-time flow of information in and around the enterprise, which enables in-time decision making. [7]

Complex event processing

Complex event processing (CEP) allows patterns of simple and ordinary events to be considered to infer that a complex event has occurred. Complex event processing evaluates a confluence of events and then takes action. The events (notable or ordinary) may cross event types and occur over a long period of time. The event correlation may be causal, temporal, or spatial. CEP requires the employment of sophisticated event interpreters, event pattern definition and matching, and correlation techniques. CEP is commonly used to detect and respond to business anomalies, threats, and opportunities. [7]

Online event processing

Online event processing (OLEP) uses asynchronous distributed event logs to process complex events and manage persistent data. [8] OLEP allows reliably composing related events of a complex scenario across heterogeneous systems. It thereby enables very flexible distribution patterns with high scalability and offers strong consistency. However, it cannot guarantee upper bounds on processing time.

Extreme loose coupling and well distributed

An event-driven architecture is extremely loosely coupled and well distributed. The great distribution of this architecture exists because an event can be almost anything and exist almost anywhere. The architecture is extremely loosely coupled because the event itself doesn't know about the consequences of its cause. e.g. If we have an alarm system that records information when the front door opens, the door itself doesn't know that the alarm system will add information when the door opens, just that the door has been opened. [7]

Semantic Coupling and further research

Event-driven architectures have loose coupling within space, time and synchronization, providing a scalable infrastructure for information exchange and distributed workflows. However, event-architectures are tightly coupled, via event subscriptions and patterns, to the semantics of the underlying event schema and values. The high degree of semantic heterogeneity of events in large and open deployments such as smart cities and the sensor web makes it difficult to develop and maintain event-based systems. In order to address semantic coupling within event-based systems the use of approximate semantic matching of events is an active area of research. [9]

Implementations and examples

Java Swing

The Java Swing API is based on an event-driven architecture. This works particularly well with the motivation behind Swing to provide user interface related components and functionality. The API uses a nomenclature convention (e.g. "ActionListener" and "ActionEvent") to relate and organize event concerns. A class which needs to be aware of a particular event simply implements the appropriate listener, overrides the inherited methods, and is then added to the object that fires the event. A very simple example could be:

publicclassFooPanelextendsJPanelimplementsActionListener{publicFooPanel(){super();JButtonbtn=newJButton("Click Me!");btn.addActionListener(this);this.add(btn);}@OverridepublicvoidactionPerformed(ActionEventae){System.out.println("Button has been clicked!");}}

Alternatively, another implementation choice is to add the listener to the object as an anonymous class and thus use the lambda notation (since Java 1.8). Below is an example.

publicclassFooPanelextendsJPanel{publicFooPanel(){super();JButtonbtn=newJButton("Click Me!");btn.addActionListener(ae->System.out.println("Button has been clicked!"));this.add(btn);}}

JavaScript

(()=>{'use strict';classEventEmitter{constructor(){this.events=newMap();}on(event,listener){if(typeoflistener!=='function'){thrownewTypeError('The listener must be a function');}letlisteners=this.events.get(event);if(!listeners){listeners=newSet();this.events.set(event,listeners);}listeners.add(listener);returnthis;}off(event,listener){if(!arguments.length){this.events.clear();}elseif(arguments.length===1){this.events.delete(event);}else{constlisteners=this.events.get(event);if(listeners){listeners.delete(listener);}}returnthis;}emit(event,...args){constlisteners=this.events.get(event);if(listeners){for(letlisteneroflisteners){listener.apply(this,args);}}returnthis;}}this.EventEmitter=EventEmitter;})();

Usage:

constevents=newEventEmitter();events.on('foo',()=>{console.log('foo');});events.emit('foo');// Prints "foo"events.off('foo');events.emit('foo');// Nothing will happen

Object Pascal

Events are one of the fundamental elements of the Object Pascal language. The uni-cast model (one-to-one) is used here, i.e. the sender sends information to only one recipient. This limitation has the advantage that it does not need a special event listener. The event itself is a pointer to a method in another object. If the pointer is not empty, when an event occurs, the event handler is called. Events are commonly used in classes that support GUI. This is not the only area of application for events, however. The following code is an example of using events:

unitMyCustomClass;interfaceusesClasses;type{definition of your own event}TAccidentEvent=procedure(Sender:TObject;constAValue:Integer)ofobject;TMyCustomObject=class(TObject)privateFData:Integer;// an example of a simple field in a classFOnAccident:TAccidentEvent;// event - reference to a method in some objectFOnChange:TNotifyEvent;// event - reference to a method in some object procedureSetData(Value:Integer);// a method that sets the value of a field in the class protectedprocedureDoAccident(constAValue:Integer);virtual;// a method that generates an event based on your own definition procedureDoChange;// a method that generates an event based on a definition from the VCL library publicconstructorCreate;virtual;// class constructor destructorDestroy;override;// class destructorpublishedpropertyData:TAccidentEventreadFDatawriteSetData;// declaration of a property in a classpropertyOnAccident:TAccidentEventreadFOnAccidentwriteFOnAccident;// exposing the event outside the classpropertyOnChange:TNotifyEventreadFOnChangewriteFOnChange;// exposing the event outside the classprocedureMultiplyBy(constAValue:Integer);// a method that uses its own definition of the eventend;implementationconstructorTMyCustomObject.Create;beginFData:=0;end;destructorTMyCustomObject.Destroy;beginFData:=0;inheritedDestroy;end;procedureTMyCustomObject.DoAccident(constAValue:Integer);beginifAssigned(FOnAccident)thenFOnAccident(Self,AValue);end;procedureTMyCustomObject.DoChange;beginifAssigned(FOnChange)thenFOnChange(Self);end;procedureTMyCustomObject.MultiplyBy(constAValue:Integer);beginFData:=FData*AValue;ifFData>1000000thenDoAccident(FData);end;procedureTMyCustomObject.SetData(Value:Integer);beginifFData<>ValuethenbeginFData:=Value;DoChange;end;end.

The created class can be used as follows:

...procedureTMyForm.ShowCustomInfo(Sender:TObject);beginifSenderisTMyCustomObjectthenShowMessage('Data has changed.');end;procedureTMyForm.PerformAcident(Sender:TObject;constAValue:Integer);beginifSenderisTMyCustomObjectthenShowMessage('The data has exceeded 1000000! New value is: '+AValue.ToString);end;...{declaring a variable that is an object of the specified class}varLMyObject:TMyCustomObject;...{creation of the object}LMyObject:=TMyCustomObject.Create;...{assigning a methods to an events}LMyObject.OnChange:=MyForm.ShowCustomInfo;LMyObject.OnAccident:=MyForm.PerformAcident;...{removing an object when it is no longer needed}LMyObject.Free;...

Challenges

One of the challenges of using event driven architecture is error handling. One way to address this issue is to use a separate error-handler processor. So, when the event consumer experiences an error, it immediately and asynchronously sends the erroneous event to the error-handler processor and moves on. Error-handler processor tries to fix the error and sends the event back to the original channel. But if the error-handler processor fails, then it can send the erroneous event to an administrator for further inspection. Note that if you use an error-handler processor, erroneous events will be processed out of sequence when they are resubmitted. [6]

Another challenge of using event driven architecture is data loss. If any of the components crashes before successfully processing and handing over the event to its next component, then the event is dropped and never makes it into the final destination. To minimize the chance of data loss, you can persist in-transit events and remove / dequeue the events only when the next component has acknowledged the receipt of the event. These features are usually known as "client acknowledge mode" and "last participant support". [6]

See also

Articles

Related Research Articles

AltiVec is a single-precision floating point and integer SIMD instruction set designed and owned by Apple, IBM, and Freescale Semiconductor — the AIM alliance. It is implemented on versions of the PowerPC processor architecture, including Motorola's G4, IBM's G5 and POWER6 processors, and P.A. Semi's PWRficient PA6T. AltiVec is a trademark owned solely by Freescale, so the system is also referred to as Velocity Engine by Apple and VMX by IBM and P.A. Semi.

In programming languages, a closure, also lexical closure or function closure, is a technique for implementing lexically scoped name binding in a language with first-class functions. Operationally, a closure is a record storing a function together with an environment. The environment is a mapping associating each free variable of the function with the value or reference to which the name was bound when the closure was created. Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.

Generic programming is a style of computer programming in which algorithms are written in terms of data types to-be-specified-later that are then instantiated when needed for specific types provided as parameters. This approach, pioneered by the ML programming language in 1973, permits writing common functions or types that differ only in the set of types on which they operate when used, thus reducing duplicate code.

In software design and engineering, the observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by calling one of their methods.

In object-oriented (OO) and functional programming, an immutable object is an object whose state cannot be modified after it is created. This is in contrast to a mutable object, which can be modified after it is created. In some cases, an object is considered immutable even if some internally used attributes change, but the object's state appears unchanging from an external point of view. For example, an object that uses memoization to cache the results of expensive computations could still be considered an immutable object.

In computer science, reflective programming or reflection is the ability of a process to examine, introspect, and modify its own structure and behavior.

The magic pushbutton is a common anti-pattern in graphical user interfaces.

In class-based, object-oriented programming, a constructor is a special type of function called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables.

<span class="mw-page-title-main">Java syntax</span> Set of rules defining correctly structured program

The syntax of Java is the set of rules defining how a Java program is written and interpreted.

In computing and systems design, a loosely coupled system is one

  1. in which components are weakly associated with each other, and thus changes in one component least affect existence or performance of another component.
  2. in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components. Subareas include the coupling of classes, interfaces, data, and services. Loose coupling is the opposite of tight coupling.

In some programming languages, const is a type qualifier that indicates that the data is read-only. While this can be used to declare constants, const in the C family of languages differs from similar constructs in other languages in that it is part of the type, and thus has complicated behavior when combined with pointers, references, composite data types, and type-checking. In other languages, the data is not in a single memory location, but copied at compile time for each use. Languages which use it include C, C++, D, JavaScript, Julia, and Rust.

Exception handling syntax is the set of keywords and/or structures provided by a computer programming language to allow exception handling, which separates the handling of errors that arise during a program's operation from its ordinary processes. Syntax for exception handling varies between programming languages, partly to cover semantic differences but largely to fit into each language's overall syntactic structure. Some languages do not call the relevant concept "exception handling"; others may not have direct facilities for it, but can still provide means to implement it.

<span class="mw-page-title-main">JavaScript syntax</span> Set of rules defining correctly structured programs

The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program.

A class in C++ is a user-defined type or data structure declared with any of the keywords class, struct or union that has data and functions as its members whose access is governed by the three access specifiers private, protected or public. By default access to members of a C++ class declared with the keyword class is private. The private members are not accessible outside the class; they can be accessed only through member functions of the class. The public members form an interface to the class and are accessible outside the class.

C++11 is a version of a joint technical standard, ISO/IEC 14882, by the International Organization for Standardization (ISO) and International Electrotechnical Commission (IEC), for the C++ programming language. C++11 replaced the prior version of the C++ standard, named C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

A property, in some object-oriented programming languages, is a special sort of class member, intermediate in functionality between a field and a method. The syntax for reading and writing of properties is like for fields, but property reads and writes are (usually) translated to 'getter' and 'setter' method calls. The field-like syntax is easier to read and write than many method calls, yet the interposition of method calls "under the hood" allows for data validation, active updating, or implementation of what may be called "read-only fields".

In computer science, a value object is a small object that represents a simple entity whose equality is not based on identity: i.e. two value objects are equal when they have the same value, not necessarily being the same object.

In programming and software design, an event is an action or occurrence recognized by software, often originating asynchronously from the external environment, that may be handled by the software. Computer events can be generated or triggered by the system, by the user, or in other ways. Typically, events are handled synchronously with the program flow. That is, the software may have one or more dedicated places where events are handled, frequently an event loop.

Event-driven SOA is a form of service-oriented architecture (SOA), combining the intelligence and proactiveness of event-driven architecture with the organizational capabilities found in service offerings. Before event-driven SOA, the typical SOA platform orchestrated services centrally, through pre-defined business processes, assuming that what should have already been triggered is defined in a business process. This older approach does not account for events that occur across, or outside of, specific business processes. Thus complex events, in which a pattern of activities—both non-scheduled and scheduled—should trigger a set of services is not accounted for in traditional SOA 1.0 architecture.

In object-oriented design, the chain-of-responsibility pattern is a behavioral design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain. A mechanism also exists for adding new processing objects to the end of this chain.

References

  1. K. Mani Chandy Event-driven Applications: Costs, Benefits and Design Approaches, California Institute of Technology, 2006
  2. Martin Fowler, Event Sourcing, December, 2005
  3. Martin Fowler, Parallel Model, December, 2005
  4. Hanson, Jeff (January 31, 2005). "Event-driven services in SOA". JavaWorld . Retrieved 2020-07-21.
  5. Sliwa, Carol (May 12, 2003). "Event-driven architecture poised for wide adoption". Computerworld . Retrieved 2020-07-21.
  6. 1 2 3 Richards, Mark. Fundamentals of Software Architecture: An Engineering Approach. O'Reilly Media. ISBN   978-1492043454.
  7. 1 2 3 4 5 6 7 8 9 10 Brenda M. Michelson, Event-Driven Architecture Overview, Patricia Seybold Group, February 2, 2006
  8. "Online Event Processing - ACM Queue". queue.acm.org. Retrieved 2019-05-30.
  9. Hasan, Souleiman, Sean O’Riain, and Edward Curry. 2012. “Approximate Semantic Matching of Heterogeneous Events.” In 6th ACM International Conference on Distributed Event-Based Systems (DEBS 2012), 252–263. Berlin, Germany: ACM. “DOI”.