Create and handle internal events in EzyPlatform
Updated at 1774884770000To ensure infinite scalability, EzyPlatform provides an internal event mechanism and event handling for admin, web, and socket components.
Objectives
- Help you understand internal events in EzyPlatform
- Help you create event sources in EzyPlatform
- Help you handle events in EzyPlatform
Introduction to Internal Events in EzyPlatform
We have three main components:
- Event class
- Event manager class
- Event handler class
How It Works
flowchart TD
A["Business code creates event data"] --> B["EventHandlerManager.handleEvent"]
B --> C["Resolve eventName from class or explicit argument"]
C --> D["Fetch handler list by eventName"]
D --> E["Handlers are already sorted by ascending priority"]
E --> F["Invoke handler.handleEventData"]
F --> G{"Is this a VoidEvent?"}
G -- Yes --> H["Continue invoking all handlers"]
H --> I["No return value needed, mainly side effects"]
G -- No --> J{"Did the handler return a non-null result?"}
J -- Yes --> K["Stop the chain and return the result immediately"]
J -- No --> L["Move to the next handler"]
L --> F
H --> M["Finish and return null"]
I --> M
In short, EzyPlatform uses
EventHandlerManager as an internal event router.-
eventNameacts as the routing key -
prioritydetermines execution order -
AbstractEventHandlerstandardizes error handling VoidEventdistinguishes between:- events that require the first valid result
- events that should be broadcast to all handlers
Event Class
EzyPlatform does not enforce a specific event class, meaning you can send any type of event with any data.
However, it provides the
VoidEvent interface to indicate that:- the system does not care about return values
- all handlers will be executed
Example:
public class MessageEvent implements VoidEvent {}
If there are 3 handlers for
MessageEvent, all 3 will execute without interruption.Event Manager – EventHandlerManager
All internal events are managed through:
public class EventHandlerManager { public <R> R handleEvent(Object data) {} public <R> R handleEvent(String eventName, Object data) {} }
Parameters:
-
eventName: event identifier (defaults to class name if not provided) -
data: any object containing event data
Injection (Admin)
@EzySingleton @AllArgsConstructor public class AdminEventExample { private final AdminEventHandlerManager eventHandlerManager; }
Or:
@Setter @EzySingleton public class AdminEventExample { @EzyAutoBind private AdminEventHandlerManager eventHandlerManager; }
Injection (Web)
@EzySingleton @AllArgsConstructor public class WebEventExample { private final WebEventHandlerManager eventHandlerManager; }
Or:
@Setter @EzySingleton public class WebEventExample { @EzyAutoBind private WebEventHandlerManager eventHandlerManager; }
Event Handler
EzyPlatform provides:
Interface
public interface EventHandler<D, R> { R handleEventData(D data); String getEventName(); int getPriority(); }
Abstract Class
public abstract class AbstractEventHandler<D, R> extends EzyLoggable implements EventHandler<D, R> { @Override public final R handleEventData(D data) { try { return doHandleEventData(data); } catch (Exception e) { return handleException(e); } } protected R doHandleEventData(D data) { processEventData(data); return null; } protected void processEventData(D data) {} protected R handleException(D data, Exception e) { return handleException(e); } protected R handleException(Exception e) { processException(e); return null; } protected void processException(Exception e) {} @Override public String getEventName() { // implementation } }
Key Methods
-
doHandleEventData: override if you want to return a result (non-null stops chain) -
processEventData: override for side-effect only (no return) -
handleException: override to return a result on error -
processException: override for error handling without return
Creating an Event Source
Add a constant:
public static final String INTERNAL_EVENT_NAME_POST_WORD_COUNT = "personal_post_word_count";
Emit event:
eventHandlerManager.handleEvent(
INTERNAL_EVENT_NAME_POST_WORD_COUNT,
EzyMapBuilder.mapBuilder()
.put("postId", dataRecord.getPostId())
.put("wordCount", dataRecord.getWordCount())
.toMap()
);
Handling Events
Example: calculate reading time from word count:
@EzySingleton @AllArgsConstructor public class AdminTimeToReadPostWordCountEventHandler extends AbstractEventHandler<Map<String, Object>, Void> { private final AdminPostMetaService postMetaService; private static final BigDecimal READ_TIME_PER_WORD = new BigDecimal("0.24"); @Override protected void processEventData(Map<String, Object> data) { long postId = (long) data.get("postId"); long wordCount = (long) data.get("wordCount"); long readTime = BigDecimal.valueOf(wordCount) .multiply(READ_TIME_PER_WORD) .longValue(); postMetaService.savePostMetaUniqueKey( postId, META_KEY_TIME_TO_READ, readTime ); } @Override public String getEventName() { return INTERNAL_EVENT_NAME_POST_WORD_COUNT; } }
Notes
- Events can be produced and handled across modules
- Events are isolated per component (admin ≠ web ≠ socket)
- Events cannot be shared across servers