[erlang-questions] Handling routing_key for topic routing in gen_server handle_info

Sébastien BRICE otb@REDACTED
Fri Aug 16 12:14:11 CEST 2019

Hello there,

I am a bit new to the Erlang Environment

I am writing an emailtesting application that filters incoming email 
with a randomly generated routing_keys on a topic exchange to make 
emails entering my system

Once they are delivered (and processed) on an queue, I want to label 
them again with the previously randomly routing_key to route them to 
another exchange to make them ready for the final consume.

This 2nd producing step is causing me real troubles

I am getting data back from a tcp socket (processed by a third-tier 
program: spamassassin) with handle_info pattern matching

I rely on a gen_server to consume messages first through the regular 
amqp_client/include/amqp_client.hrl Library

I use handle_info in my gen_server behaviour and then pattern match on 
the parameters.

Detecting delivered AMQP message is done through function heads 
(records) in handle_info callback

***My gen_server****
handle_info({#'basic.deliver'{routing_key=Key, consumer_tag=Tag}, 
Content}, State) ->
     #amqp_msg{props = Properties, payload = Payload} = Content,
     #'P_basic'{message_id = MessageId, headers = Headers} = Properties,
     {noreply, State};
handle_info(Msg, State) ->
     case Msg of
         {_,_,Data} ->
         {_,_} ->
     {noreply, State}.

***send_to_spamassassin function ***
     calcule_score(Message) ->
     case gen_tcp:connect("localhost", 783, [{mode, binary}]) of
         {ok, Sock} ->
             gen_tcp:send(Sock, Message2);
         {error,_} ->
             io:fwrite("Connection error! Quitting...~n")

TCP socket is nice to talk with spamassassin, it returns me a 3-tuple 
with binary string data like that:

{tcp,#Port<0.55>,<<"SPAMD/1.1 0 EX_OK\r\nContent-length: 564\r\nSpam: 
True ; 7.9 / 5.0\r\n\r\nReceived: from localhost by 
XXXX.ikexpress.com\n\twith SpamAssassin (version 3.4.2);\n\tThu, 15 Aug 
2019 21:44:12 +0200\nX-Spam-Checker-Version: SpamAssassin 3.4.2 
(2018-09-13) on\n\tXXXXX.ikexpress.com\nX-Spam-Flag: YES\nX-Spam-Level: 
*******\nX-Spam-Status: Yes, score=7.9 required=5.0 
autolearn=no\n\tautolearn_force=no version=3.4.2\nMIME-Version: 
1.0\nContent-Type: multipart/mixed; 

The loop in the second handle_info match OK the answer from the 
listening gen_tcp server, but I have to do the packaging to send it to a 
topic Exchange (topic_scored_email exchange)

main(Argv) ->
     {ok, Connection} = 
amqp_connection:start(#amqp_params_network{virtual_host = <<"/">>}),
     {ok, Channel} = amqp_connection:open_channel(Connection),
     amqp_channel:call(Channel, #'exchange.declare'{exchange = 
<<"topic_scored_email">>,type = <<"topic">>}),
     {RoutingKey, Message} = case Argv of
     amqp_channel:cast(Channel,#'basic.publish'{exchange = 
<<"topic_scored_email">>,routing_key = RoutingKey},#amqp_msg{payload = 

First issue is type of the data (binary string) but I guess it can be 
workarounded using BIF binary_to_tuple or stuff like that.

What I struggle to understand is how I could pass the righ RoutingKey, 
since Erlang is functionnal, there is no side effect or assignation.

That change in format data (AMQP --> raw tcp --> then AMQP again) seems 
impossible (to me) to achieve with OTP abstraction

However I would like to reassemble every processed message with the 
right routing key matched 5 lines above.

How could I modify my code, to do that ? I come from imperative language 
and reach my limit here…


PS I know it is more a rabbitmq issue and I might be more successful to 
post on stackoverflow or rabbitmq google groups but I feel 
#Erlang-questions could come handy on that topic

More information about the erlang-questions mailing list