Create and handle internal events in EzyPlatform

Updated at 1774884770000
To 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.
  • eventName acts as the routing key
  • priority determines execution order
  • AbstractEventHandler standardizes error handling
  • VoidEvent distinguishes 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

Table Of Contents