EMG router connector Print
Monday, 17 October 2011

EMG 5.2 introduces a new type of connector, defined by specifying "PROTOCOL=ROUTE".

This connector type enables implementation of custom routing logic decoupled from receiver process for incoming messages.

Normally when a message is received routing logic is applied before response is sent back to client. This may be problematic if routing process depends on external systems and may take a long time to complete. For example if HLR lookups are necessary for routing process and subscriber is not currently available.

By adding an intermediate route-connector to which messages are routed in first step, the response can be sent back to client immediately and before routing process is completed.

A queue can be allowed to build on the intermediate connector and several parallel worker threads can process this queue.

It is possible to limit the total queue size allowed in EMG by using keywords MAXTOTALQUEUESIZE_SOFT and MAXTOTALQUEUESIZE which will throttle and reject incoming messages when total queue size within EMG reaches specified limits.

emg-router-flow

Plugin hooks and router connector

The "router" connector executes plugin hooks, but a bit differently from a normal connector. When a message is extracted from connector queue and processed the "before_send" plugin hook will first be executed. This hook can be used as a pre-processor and, for example, perform lookups and add results as additional message options which can later be used in the "route" plugin hook.

By returning a non-zero return code from "before_send", and by using a connector retry scheme, different retry algorithms can be applied for different lookup results.

After a message has been processed by "before_send" plugin hook the "route" plugin hook will be executed. Here the actual routing logic can be applied and the name of the outgoing, target, connector should be returned.

Re-route

When a connector goes into state "ERROR" all messages in queue for that connector will be re-routed. The re-route mechanism extracts each message in the connector queue and transfers it back to the "routing" step on the connector where it was first received.

In this scenario it will be back to the incoming connector "smpp-in1" where message was received and from there it will, once again, be routed to the "router" connector queue. The "router" connector will process the messages and the "before_send" and "route" plugin hooks will be executed.

If additional message options were added when lookup in "before_send" was run first time we now have the possibility of either running the lookup again or skip that step. Some logic to determine how long time has passed since previous lookup may be implemented.

Sample configuration

This is not a complete configuration but only snippets relevant for scenario.

File: server.cfg

ROUTING=routing

PLUGIN router-plugin <
LIBRARY=router-plugin.pl
INSTANCES=10
>

CONNECTOR smpp-in1 <
TYPE=INCOMING
PROTOCOL=SMPP
ADDRESS=0.0.0.0:2776
INSTANCES=10
USERS=users
>

CONNECTOR router <
PROTOCOL=ROUTE
INSTANCES=10
PLUGIN=router-plugin
RETRYSCHEME=retry.router
>

CONNECTOR smsc1-smpp <
TYPE=OUTGOING
PROTOCOL=SMPP
ADDRESS=10.0.0.1:2776
INSTANCES=1
USERNAME=user1
PASSWORD=secret1
>

CONNECTOR smsc2-ucp <
TYPE=OUTGOING
PROTOCOL=SMPP
ADDRESS=10.0.0.2:5000
INSTANCES=1
USERNAME=user2
PASSWORD=secret2
>

File: routing

# Route all messages received on "smpp-in1 to "router"
smpp-in1 router

File: retry.router

#command
#    error
#         retrytime
#             connects
#                 maxsleep
#                     hold delay (secs)
#                         1:good message, 2:bad domain, 4:bad connector
M*    1    1    1    1    5    1
M*    2    1    1    1    60   1
M*    3    1    1    1    3600 1

File: plugin-perl.pl

sub before_send {
  my ($request, $response) = @_;
  my $q = ${$request}{'qe'};
  my $destaddr = $q->{'DESTADDR'};

  # If not already set do HLR lookup
  if(!defined($q->{'0x2001'})) {
    $mccmnc = hlr_lookup($destaddr);
    if(!defined($mccmnc)) {
      return 1;
    }
    $q->{'0x2001'} = $mccmnc;
  } else {
    # We could do something on re-route
  }

  return 0;
}

sub route {
  my ($request, $response) = @_;
  my $q = ${$request}{'qe'};

  if($q->{'0x2001'} eq '24007') {
    $route = 'smsc1-ucp';
  } else {
    $route = 'smsc2-smpp';
  }
  $response->{'route'} = $route;

  return 0;
}

Sequence diagram: Plugin calls

 

emg-seqdiagram-plugincalls