Service Bus topics - azure-servicebus-topics

I have a springboot micrservices application that needs to subscribe to topic and all copies of the container should get the message. I am used to activemq where you can connect directly to the topic and all containers get the message.
I set my appliation.yaml like:
servicebus:
connection-string: ${AZURE_SERVICE_BUS_URL}
idle-timeout: 1800000
pricing-tier: standard
topic-client-id: ${AZURE_SERVICE_BUS_TOPIC_CLIENT_ID}
listener:
subscription-durable: false
I set the listener as:
#JmsListener(destination = "edge-bindermgmt-request-state", containerFactory = "topicJmsListenerContainerFactory")
public void receiveMessage(RequestProcessingStateChange requestProcessingStateChange){
log.info("Received: {}", requestProcessingStateChange);
}
With the following I am only getting the message in one copy of the service:
#JmsListener(destination = "edge-bindermgmt-request-state", containerFactory = "topicJmsListenerContainerFactory",
subscription = "edge-bindermgmt-request-state-subscription")
public void receiveMessage(RequestProcessingStateChange requestProcessingStateChange){
log.info("Received: {}", requestProcessingStateChange);
}
So what I want is to setup the subscription on the fly, rather than having to set it up in:
screenshot of subscriptions page

If anyone else is wondering, you need the premium subscription for Service Bus for that. I ended up going with ActiveMQ instead.

Related

Has anyone built an integration with any SMS Receivers?

I want to be able to send a text message to some number and then (upon receiving the text) basically just send a post request off to a different service after receiving the text. Does anyone know of a service I could use to set this up? Would like for it to be as fast as possible
Here's a summary of the steps to setup a sample app:
Navigate to Amazon SNS Service → Topics
Enter Name and create a new Topic
For the newly created topic, create a subscription where the Protocol is AWS Lambda (see image1 below)
Navigate to Amazon Pinpoint Service, create new Pinpoint application
Enable SMS & voice feature for this Pinpoint application
Get a new Long Code (long code price is $1/month)
For the long code, Enable two-way SMS, select the Choose an existing SNS topic option and select the SNS topic created in Step 2 above (see image2 below)
Finally, now you can send a message to that phone number from your phone and it will trigger your lambda function. In your lambda function, you can send a POST request to a different service or do whatever else. You can also respond back to the user's message - see example below.
Here's an example of how to send a message using Amazon Pinpoint in Java:
public void sendSMS(String pinpointPhoneNumber, String userPhoneNumber, String messageContent) {
// define who the message is going to and via what platform
Map<String, AddressConfiguration> addressMap = new HashMap<>();
addressMap.put(userPhoneNumber, new AddressConfiguration().withChannelType(ChannelType.SMS));
SMSMessage smsMessage = new SMSMessage();
smsMessage.setOriginationNumber(pinpointPhoneNumber);
smsMessage.setMessageType(MessageType.TRANSACTIONAL);
smsMessage.setBody(messageContent);
// add sms message to the direct message config
// this can have many other types of messages
DirectMessageConfiguration directMessageConfiguration = new DirectMessageConfiguration()
.withSMSMessage(smsMessage);
// put the phone numbers and all messages in here
MessageRequest messageRequest = new MessageRequest()
.withAddresses(addressMap)
.withMessageConfiguration(directMessageConfiguration);
// create send request
SendMessagesRequest sendMessagesRequest = new SendMessagesRequest()
.withApplicationId("put-pinpoint-app-id-here")
.withMessageRequest(messageRequest);
// send the message
AmazonPinpoint pinpointClient = AmazonPinpointClientBuilder.standard().build();
SendMessagesResult sendMessagesResult = pinpointClient.sendMessages(sendMessagesRequest);
MessageResponse messageResponse = sendMessagesResult.getMessageResponse();
}

Multiple SQS Listeners from different AWS regions

We are currently consuming a single SQS queue to process messages.
However as extension of functionality, we need to support multiple regions with same queue name.
Current implementation of jmsListener is tied to a given SQS queue in a given region as below:
SQSListener.java
#Component
public class SQSListener {
#Override
#JmsListener(destination = "${QueueName}", concurrency = "${JmsThreadCount}")
public void onMessage(Message message) throws JMSException {
}
SQSConfiguration.java
#Component
#EnableJms
public class SQSConfig {
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = null;
try {
factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(getSqsConnectionFactory()); //passes credentials in local method call
factory.setDestinationResolver(new DynamicDestinationResolver());
factory.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
} catch (Exception e) {
logger.error(e.getLocalizedMessage());
}
return factory;
}
}
Application.properties
QueueName=xyz
JmsThreadCount=1-5
Regions=us-east-1, us-west-2 #*(newly added region)*
How can I make it generic to create multiple listener class implementations by regions specified in the configurations ?
Though there is no direct way using spring framework's annotations to create listeners to listen to multiple queue's in multiple AWS regions (same queue name in multiple AWS regions), I was able to solve above problem by programmatic configuration of JMS Container Factory beans for each region, JMS Templates for each region, and JMS Listeners for each region.
I will post sample code in next few days, that may be useful to the community.
You can listen to SQS from different region . If you provide not the queue name but full https url of the SQS . I have applied this in my application and it worked
eg SQS http URL - https://sqs.us-west-2.amazonaws.com/YOURACCOUNTNUMBER/YOURQUEUENAME
#SqsListener(value = "https://sqs.us-west-2.amazonaws.com/123456789/MYQUEUENAME
", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
protected void queueListener(String dataFomSQS, #Header("Acknowledgment") Acknowledgment acknowledgment) {}

Receive Azure topic messages into Web Job?

How do we pump out messages from service bus topic's subscription.
I have been able to receive from service bus queue successfully.
public class Functions
{
public static void ProcessQueueMessage([ServiceBusTrigger("mseoikeyword")] BrokeredMessage message, TextWriter log)
{
string strMsg;
strMsg = message.GetBody<string>();
log.WriteLine(strMsg);
}
}
Using the same trigger with topic path and subscription name as per documentation.
Ensure topic and subscription exist as they will not be created by the trigger.

How to send Firebase Cloud Message with AWS SNS? [duplicate]

I am using AWS resources for my android project, I am planning to add push notification service for my project with AWS SNS.there are few questions bothering me much. I did not find any questions regarding these, except one or two but with unclear explanations.
1.Does AWS support FCM? SNS work with GCM. But Google recommends to use FCM instead of GCM. I did not find AWS supporting FCM.
2.Do AWS store messages (or data) into their databases even after sending push notifications?
3.I tried putting FCM api key in SNS application platform, it is showing invalid parameters why?
FCM is backwards compatible with GCM. The steps for setting up FCM on AWS are identical to the GCM set up procedure and (at least for the moment) FCM works transparently with GCM and SNS with respect to server-side configuration.
However, if you are sending data payloads to the Android device they will not be processed unless you implement a client side service that extends FirebaseMessagingService. The default JSON message generator in the AWS console sends data messages, which will be ignored by your app unless the aforementioned service is implemented. To get around this for initial testing you can provide a custom notification payload which will be received by your device (as long as your app is not in the foreground)
There are GCM-FCM migration instructions provided by Google however the changes you need to make are predominantly on the App side.
The steps you need to follow to test GCM/FCM on your app with SNS are:
Create a Platform Application in SNS, selecting Google Cloud Messaging (GCM) as the Push Notification Platform, and providing your Server API key in the API key field.
Select the Platform Application and click the Create platform endpoint button.
Provide the InstanceID (Device Token) generated by your app. You must extend the FirebaseInstanceIDService and override the onTokenRefresh method to see this within your Android App. Once you have done this, uninstall and reinstall your app and your token should be printed to the Debug console in Android Studio on first boot.
Click the Add endpoint button.
Click on the ARN link for your platform application.
Select the newly created Endpoint for your device and click the Publish to endpoint button.
Select the JSON Message Format, and click the JSON message generator button.
Enter a test message and click the Generate JSON button
Now comes the "gotcha part".
The message that is generated by SNS will be of the form:
{
"GCM": "{ \"data\": { \"message\": \"test message\" } }"
}
As we mentioned earlier, data payloads will be ignored if no service to receive them has been implemented. We would like to test without writing too much code, so instead we should send a notification payload. To do this, simply change the JSON message to read:
{
"GCM": "{ \"notification\": { \"title\": \"test title\", \"body\": \"test body\" } }"
}
(For more information about the JSON format of an FCM message, see the FCM documentation.)
Once you have done this, make sure your app is not running on the device, and hit the Publish Message button. You should now see a notification pop up on your device.
You can of course do all this programmatically through the Amazon SNS API, however all the examples seem to use the data payload so you need to keep that in mind and generate a payload appropriate to your use case.
Now you can go to your firebase console (https://console.firebase.google.com/) select your project, click the gear icon and choose project settings, then click on the cloud messaging tab...
You'll see the legacy Server Key which is the GCM API Key and you'll have the option to generate new Server Keys which are the FCM versions
SNS will accept both versions but their menu option is still categorizing it under GCM
Here is picture for your reference:
Note that you can "accidentally" remove your Server Keys but the Legacy server key is not deletable. Also, if you click the add server key button, you'll get a new server key BELOW the first one, WITH NO WARNING! ...Nice job Google ;)
One more additional note to Nathan Dunn's great answer.
How to send data with the notification from SNS to Firebase.
We need to add data to the Json (inside the notification):
{
"default": “any value",
"GCM": "{ \"notification\": { \"body\": \”message body\”, \”title\”: \”message title \”, \"sound\":\"default\" } , \"data\" : {\”key\" : \”value\", \”key2\" : \”value\” } }”
}
In your FirebaseMessagingService implementation (Xamarin example)
public override void OnMessageReceived(RemoteMessage message)
{
try
{
var body = message?.GetNotification()?.Body;
var title = message?.GetNotification()?.Title;
var tag = message?.GetNotification()?.Tag;
var sound = message?.GetNotification()?.Sound;
var data = message?.Data
foreach (string key in data.Keys)
{
// get your data values here
}
}
catch (Exception e)
{
}
}
I tried to use solution with notification payload instead of data, but I did not receive push notifications on the mobile device. I found this tutorial https://youtu.be/iBTFLu30dSg with English subtitles of how to use FCM with AWS SNS step by step and example of how to send push notifications from AWS console and implement it on php with aws php sdk. It helped me a lot.
Just an additional note to Nathan Dunn's Answer: to add sound use the following JSON message
{
"GCM": "{ \"notification\": { \"text\": \"test message\",\"sound\":\"default\" } }"
}
It took me a while to figure out how to send the notification with the right payload (publish to topic). So I will put it here.
private void PublishToTopic(string topicArn)
{
AmazonSimpleNotificationServiceClient snsClient =
new AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.EUWest1);
PublishRequest publishRequest = new PublishRequest();
publishRequest.TopicArn = topicArn;
publishRequest.MessageStructure = "json";
string payload = "\\\"data\\\":{\\\"text\\\":\\\"Test \\\"}";
publishRequest.Message = "{\"default\": \"default\",\"GCM\":\"{" + payload + "}\"}";
PublishResponse publishResult = snsClient.Publish(publishRequest);
}
Amazon does support FCM as all previous code has been migrated from GCM to FCM. Below article explains in detail.
Article Published by Amazon
To answer the questions:
AWS SNS does support FCM.
No AWS does not store messages after sending push notifications.
For a detailed tutorial on setting up FCM with SNS please read this article.

AWS SNS Java program to subscribe

I am publishing a String message as message payload using SNS notification from Raspberry Pi using Python program and I want to pass that message payload to a Lambda function.
I have configured the requirement in the SNS console on AWS i.e., I have created a topic and added the lambda function to its subscribers.
Now, I want to get that message payload in the lambda function. But I can't find any method that can help me do that. For example, something like getMessage or something similar to that.
So my questions are: Since I have configured the publishing and subscription on AWS, can I assume that the clients are connected and if I publish a message I should be getting that at the subscriber's end which is my lambda function here?
Also, what's the technique in which I can get the message payload in my lambda function?
I am adding the below as per cjwfuller's suggestion.
Below I have written down the method for publishing in Python
client_boto = boto3.client('sns', aws_access_key_id='###',
aws_secret_access_key='###', region_name='us-west-2')
REGION = 'us-west-2'
TOPIC = 'arn:aws:sns:us-west-2:***:topic_name'
MSG = ntpath.basename(f_string)
SUBJECT_boto = 'File Name'
pub =client_boto.publish(TopicArn = TOPIC, Message = MSG,
Subject=SUBJECT_boto)
I am writing the subscribing code in Java.
Since my lambda func is already subscribed to it on AWS console,
should my Java program include the subscription again or is there a
way to get the msg payload directly.
Which language are you writing the function in? JavaScript as an example:
exports.myHandler = function(event, context, callback) {
console.log("value1 = " + event.key1);
console.log("value2 = " + event.key2);
// ...
}
Source: http://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-handler.html
It's useful testing the sort of stuff in the AWS Lambda console before writing all the code.
Since I have configured the publishing and subscription on AWS, can I assume that the clients are connected
Clients aren't really "connected", they're simply subscribed to a topic.
publish a message I should be getting that at the subscriber's end which is my lambda function here?
Sounds like you're doing the right sort of thing - posting example code will help us come up with more precise answers.
On searching, I have found the class for SNSEvent which is, https://github.com/aws/aws-lambda-java-libs/blob/master/aws-lambda-java-events/src/main/java/com/amazonaws/services/lambda/runtime/events/SNSEvent.java
This Class contains all the methods related to and needed to get the message payload.
The Lambda function handler in Java goes something like this,
example;
public void handleRequest(SNSEvent input, Context context){
String this_takes_message=input.getRecords().get(0).getSNS().getMessage();
}