Skip to content

Flows

Flow is composition of functions (build-in or provided via customization) that performs some complex logic. Flows can be further composed into final processing flow.

The data between functions in a flow (or between flows) are exchanges via spring integration channels which can me in-memory or configured to some message broker like RabitMQ or Kafka

Notification processing variants

Notiflow can operate in both PUSH and PULL mode in terms of data that can produce notification

  • PUSH: Notiflow exposes REST API that can be actively called to send Input event/Notification intent/Message to notiflow and trigger notification processing

    Example: There is a new order in your online shop and you want to send confirmation to your customer. In that case you web shop send Input event to dedicated REST API and notiflow will handle the notification aspect

  • PULL: Notiflow can be configured to fetch data from data source (Database, REST API,..) and decide if the data meet some criteria that could lead to notification

    Example: if you have a system with contracts that have expiration date, you can configure notiflow to generate notification one month before expiration.

    You can find full technical description of this flow in the Notification polling chapter

Top-level flows

The default configuration of notiflow consists of 4 processing stages

  1. EventReceiver: Receive and persist input application Event
  2. InputEventExtensionConverting: Event to Intent/Message conversion
  3. MessageProcessingFlow: Message persistance, formatting, ..
  4. Sending: Sending different types of messages via dedicated channel

This is high level and simplified view on default notiflow message processing.

standard-flow

If notiflow is configured to consume data from external data sources (PULL mode) there is an additional flow for each data source that is created dynamically based on notiflow configuration. There is a step where the data are converted into one either Input event/Notification intent/Message after which the notification follows standard processing.

Notification processing (PUSH)

The input to standard-flow (and thus start of input processing) can be done by calling one of tree dedicated API endpoints

Which one of these three types is selected by the client depends on the particular use-case.

  • Input event: This is used when you want to use notiflow as receiver of any specify application event your application can produce. This can be events like
    • "New order" in web shop
    • "Low inventory" in warehouse
    • User request for 2-factor authentication
    • ... and any other you might need

The intension using this approach is to offload as much of the notification processing from the client application as possible. The application focuses on its core business and emits event about what happen. The payload stored in [Input event] can be completely custom and unknown to notiflow

Input event routing flow

standard-flow

Input event routing flow is responsible for

  • Receive an event and return control to the caller as soon as possible
    • Receive an event
    • persist the event
    • return controls to the caller as soon as event persisted in notiflow DB
  • Poll for events which should start processing and route them based on the notiflow configuration for input event routing for further processing

This step is only active if client what to use event as a starting point for notification processing

Input event extension converting flow

input-event-extension-converting-flow

This flow is a place of common customization. It main purpose is

Because the payload in event is not know to notiflow, client has to provide custom implementation of such conversion. This is done by implementing InputEvent2MessageConverterExtension interface. For example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
        @Bean
        public InputEvent2MessageConverterExtension event2Message() {
            return new InputEvent2MessageConverterExtension () {

                @Override
                public Optional<PayloadValidationException> canHandle(GenericEvent payload) {
                    if (payload.getPayloadAsPojo() instanceof TestPayload) {
                        return Optional.empty();
                    }

                    return Optional.of(new PayloadValidationException("No test payload"));                  
                }

                @Override
                public List<com.obj.nc.domain.message.Message<?>> convertEvent(GenericEvent event) {                    
                    EmailMessage email1 = new EmailMessage();
                    email1.addReceivingEndpoints(
                        EmailEndpoint.builder().email("test@objectify.sk").build()
                    );
                    email1.getBody().setSubject("Subject");
                    email1.getBody().setText("text");

                    List<com.obj.nc.domain.message.Message<?>> msg = Arrays.asList(email1);

                    return msg;
                }               
            };
        }

InputEvent2MessageConverterExtension implementation has to be registered as Spring @Bean

Intent processing flow

TODO

Message processing flow

message-processing-flow The responsibility of this flow is to

  • perform journaling for all messages which are about to be send. This includes persistance of message and information about recipient of the message.
  • route the message to type dependent sender

This flow has API that allows to interact with it. Example:

1
2
3
4
5
6
7
8
 @Autowired private MessageProcessingFlow msgFlow;

 void exampleSendMessage()  {
        EmailMessage msg = ...

        // when
        msgFlow.processMessage(msg);
 }

Email processing flow

email-processing-flow The responsibility of this flow is to

This flow has API that allows to interact with it. Example:

1
2
3
4
5
6
7
 @Autowired private EmailProcessingFlow emailSendingFlow;

 void exampleSendFormattedEmail()  {
        EmailMessageTemplated<?> email = ...
        emailSendingFlow.formatAndSend(email);
        ...
 }
or
1
2
3
4
5
6
7
8
9
@Autowired private EmailProcessingFlow emailSendingFlow;

void exampleSendEmail() {
    EmailMessage email = ...

    EmailMessage emailSent = emailSendingFlow
            .sendEmail(email)
            .get(1, TimeUnit.SECONDS);
}

SMS processing flow

sms-processing-flow The responsibility of this flow is to

MailChimp processing flow

mailchimp-processing-flow The responsibility of this flow is to

Push message processing flow

push-processing-flow The responsibility of this flow is to

Error handling flow

error-handling-flow

In the case of exception in any function participating in a flow, the message that caused the error is received by this channel with the information about which step was the last that failed. This flow is responsible for

  • resurrection af the failed message and execution of retry

For this to work in any situation, transaction boundaries for steps in flows have to be carefully defined

External data-source notification data polling (PULL)

pull-flow You are able to configure data sources that provide notiflow with arbitrary data. You can then configure conditions to check against theses data and if matched notiflow will trigger notification processing based on further configuration. This mode is useful if you have application with for example contracts or orders and you want to be notified one month before contract expires.

Delivery Info flows

delivery-info-flow These flows are responsible for persistance of various journaling information. They listen on predefined topics and document delivery information for given event, intent and message

The information is later used in notiflow UI for statistics and analytics

Test mode flow

This is an internal flow which is used in test mode. Its responsibility is to

  • Wait for certain time for messages which should have been send if test mode was not active
  • Aggregate them into single digest Email message
  • Send aggregated email to predefined recipient