Service Broker - How to response the message to different queue - sql-server

I'm new to Service Broker
Message Type
CREATE MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c03/RequestMessage]
VALIDATION = WELL_FORMED_XML
GO
CREATE MESSAGE TYPE [http://ssb.csharp.at/SSB_Book/c03/ResponseMessage]
VALIDATION = WELL_FORMED_XML
GO
Contract
CREATE CONTRACT [http://ssb.csharp.at/SSB_Book/c03/HelloWorldContract]
(
[http://ssb.csharp.at/SSB_Book/c03/RequestMessage] SENT BY INITIATOR,
[http://ssb.csharp.at/SSB_Book/c03/ResponseMessage] SENT BY TARGET
)
GO
Queue
CREATE QUEUE InitiatorQueue
WITH ACTIVATION
(
STATUS = ON,
PROCEDURE_NAME = [ProcessResponseMessage],
MAX_QUEUE_READERS = 1,
EXECUTE AS SELF
)
CREATE QUEUE TargetQueue
WITH ACTIVATION
(
STATUS = ON,
PROCEDURE_NAME = [ProcessRequestMessage],
MAX_QUEUE_READERS = 1,
EXECUTE AS SELF
)
Service
CREATE SERVICE InitiatorService
ON QUEUE InitiatorQueue
(
[http://ssb.csharp.at/SSB_Book/c03/HelloWorldContract]
)
GO
CREATE SERVICE TargetService
ON QUEUE TargetQueue
(
[http://ssb.csharp.at/SSB_Book/c03/HelloWorldContract]
)
GO
Codes above are the example.
The question is I want to response the message to another queue(ErrorQueue for example) instead of InitiatorQueue. I've did research on Google but I can't find any resources that related to my question.
I've some idea but don't know if it's working:
Add another message type into Contract:
[http://ssb.csharp.at/SSB_Book/c03/ErrorMessage] SENT BY INITIATOR
But I don't know whether to set it as INITIATOR, TARGET or ANY
Create another Contract for it, if this is the solution please provide an example.
Thanks

The thing processing messages on your queue can make the choice as to what to do. If you want to send to a different queue, you'll need to send on a different conversation though because sending on the same conversation as the one the original message came in on will send it back to the place that sent the message. You'll need another message type, contract, queue, and service to send that error message to. Let me know if that's not enough to get you going and I can elaborate a little further.

Related

ServiceBroker - What is sense of types of message?

Can anyone to tell me one thing ?
It is about ServiceBroker.
https://gallery.technet.microsoft.com/scriptcenter/Using-Service-Broker-for-360c961a
Following this short tutorial we can come across two thnigs:
CREATE MESSAGE TYPE [//SBM/RequestMessage] VALIDATION=WELL_FORMED_XML;
CREATE MESSAGE TYPE [//SBM/ReplyMessage] VALIDATION=WELL_FORMED_XML;
What is aim of this stuff ? What benefit from separating messages to two types ? And second thing: Is it possible to check if queue was disabled by poison ? I know that then queue is blocked, but I would like to be able to check it.
One thing I use message types for is to know how I should process the message without actually having to look at the message itself. Let's say we're creating a system that will deal with conversations from disparate applications that service both the HR and Finance teams. You could argue that those belong in separate queues, but let's assume that all of those messages are going into one queue. In the procedure that I use to dequeue messages from the queue, I would have something like this (simplified):
declare #message_type_name sysname, #message_body xml);
RECEIVE TOP (1)
#message_type_name = [message_type_name],
#message_body = CAST([message_body] AS XML)
FROM [repl].[CoreQueue]
IF (#message_type_name = 'TimeOffRequest')
EXEC dbo.ProcessTimeOffRequest #message_body;
ELSE IF (#message_type_name = 'ReimbursementRequest')
EXEC dbo.ProcessReimbursementRequest #message_body;
Note I'm employing some anti-patterns here (RECEIVEing only one message at a time, no error handling, etc) in the interest of clarity around your actual question.
Because I know something about the content of the message based on the message type, I can quickly route the message to something that can handle it. Add to that the ability to bundle message types into contracts which can be prioritized with broker priorities and you have a fairly flexible system.

Multiplexing Service Broker messages

I notice in the documentation for the SEND statement that it allows for sending the same message on multiple conversation handles at once. Let's say that in my situation, the number of places I want to send a given message is small (fewer than 5), but every message I want to send should go to all of those places. Is there any practical difference between the following:
declare #ch1 uniqueidentifier,
#ch2 uniqueidentifier,
#ch3 uniqueidentifier,
#message xml;
-- approach #1
send on conversation (#ch1, #ch2, #ch3)
message type [foo]
(#message);
-- approach #2
send on conversation (#ch1)
message type [foo]
(#message);
send on conversation (#ch2)
message type [foo]
(#message);
send on conversation (#ch3)
message type [foo]
(#message);
SEND ON (#h1, #h2, #h3, ... , #hN) is going to store the message body only once in sys.transmission_queue. As opposed to SEND ON (#h1), SEND ON (#h2), ... , SEND ON (#hN) which will store the message body N times. This is, basically, the real difference. If the message body is of significant size it can have noticeable impact on perf.
For local delivery, when sys.transmission_queue is usually not involved, there will be no significant difference.
I depends on you needs, As you say you have only five conversion you can go both ways . No difference between them... But here is the catch
Do you relay want to check your message individually(whether it went or not) OR you want to rollback from certain case or person
Do you want to count or do something on the sending process
Your 1st approach is like a machine gun.In small case it wont create pressure or data lose in a server but in large case i can not give you the guaranty(i mean Like machine gun, Server do jam ).
Messages in the transmission queues for an instance are transmitted in sequence based on:
The priority level of their associated conversation endpoint.
Within priority level, their send sequence in the conversation.

How to make sure that email is not sent twice with task queue usage?

I would like to change my GAE app logic and to start emails sending with task queue usage.
Currently I have a cron job, which runs each 15 minutes and read messages to be sent from the datastore:
class SendMessagesHandler(webapp2.RequestHandler):
def get(self):
emails_quota_exceeded = models.get_system_value('emails_quota_exceeded')
if emails_quota_exceeded == 0 or emails_quota_exceeded == None:
messages = models.get_emails_queue()
for message in messages:
try:
...
email.send()
models.update_email_status(message.key.id()) # update email status indicating that the mail has been sent
except apiproxy_errors.OverQuotaError, error_message:
models.set_system_value(what='emails_quota_exceeded', val=1)
logging.warning('E-mails quota exceeded for today: %s' % error_message)
break
else:
logging.info('Free quota to send e-mails is exceeded')
If I use task queues, then I'll get something like:
for message in messages:
taskqueue.add(url='/sendmsg', payload=message)
In this scenario it is possible that the same message will be sent twice (or even more times) - for ex., if it wasn't sent yet, but cron job was executed second time.
If I update email status immediately after adding the message to the queue:
for message in messages:
taskqueue.add(url='/sendmsg', payload=message)
models.update_email_status(message.key.id()) # update email status indicating that the mail has been sent
then it is possible that the message will never be sent. For ex., if exception happened during e-mail sending. Understand that the task will be retried, but in case quota is exceeded for today, then retries will not help.
I think I can also re-read the status of each message at task queue before trying to sent it, but it will cost me additional read operations.
What's the best way to handle it?
Giving your task a name including the key.id() will prevent it from being sent twice:
task_name = ''.join(['myemail-', str(mykey)])
try:
taskqueue.Task(
url="/someURL/send-single-email",
name=task_name,
method="POST",
params={
"subject": subject,
"body": body,
"to": to,
"from": from }
).add(queue_name="mail-queue")
except:
pass #throws TombstonedTaskError(InvalidTaskError) if tombstoned name used.
There may be times when you want to send follow-up emails for messages with the same key. Therefore, I would recommend adding a date or datetime stamp to the task name. This will allow you to send other messages of the same key at a later time:
task_name = ''.join(['myemail-', str(mykey), str(datetime.utcnow()-timedelta(hours=8))]).translate(string.maketrans('.:_ ', '----'))

multiple emails sent by sp_db_sendmail when run as SSIS package

I've a procedure which generates a tab delimited text file and also sends an email with a list of students as attachment using msdb.dbo.sp_send_dbmail.
When I execute the procedure thoruhg SQL server management studio, it sends only one email.
But I created a SSIS package and scheduled the job to run nightly. This job sends 4 copies of the email to each recipient.
EXEC msdb.dbo.sp_send_dbmail #profile_name = 'A'
,#recipients = #email_address
,#subject = 'Error Records'
,#query = 'SELECT * FROM ##xxxx'
,#attach_query_result_as_file = 1
,#query_attachment_filename = 'results.txt'
,#query_result_header = 1
,#query_result_width=8000
,#body = 'These students were not imported'
I've set following parameters to 0 (within database mail configuration wizard), to see if it makes any difference. But it didn't resolve the problem.
AccountRetryAttempts 0
AccountRetryDelay 0
DatabaseMailExeMinimumLifeTime 0
Any suggestions?
I assume you have this email wired up to an event, like OnError/OnTaskFailed, probably at the root level.
Every item you add to a Control Flow adds another layer of potential events. Imagine a Control Flow with a Sequence Container which Contains a ForEach Enumerator which contains a Data Flow Task. That's a fairly common design. Each of those objects has the ability to raise/handle events based on the objects it contains. The distance between the Control Flow's OnTaskFailed event handler and the Data Flow's OnTaskFailed event handler is 5 objects deep.
Data flow fails and raises the OnTaskFailed message. That message bubbles all the way up to the Control Flow resulting in email 1 being fired. The data flow then terminates. The ForEach loop receives signal that the Data Flow has completed and the return status was a failure so now the OnTaskFailed error fires for the Foreach loop. Repeat this pattern ad nauseum until every task/container has raised their own event.
Resolution depends, but usually folks get around this by either only putting the notification at the innermost objects (data flow in my example) or disabling the percolation of event handlers.
Check the solution here (it worked for me as I was getting 2 at a time) - Stored procedure using SP_SEND_DBMAIL sending duplicate emails to all recipients
Change the number of retries from X to 0. Now I only get 1 email. It'll be more obvious if your users are getting 4 emails, exactly 1 minute apart.

how to communicate between two clients using channel API?

I've successfully implemented the channel api to create the connection between browser and app engine server.
I want to ask what will be the way to send message from the second client to the first client.
I'm not getting the actual algorithm.
The client_id you used to create the connection to the app engine server is what you need to send a message to another client_id. Either persist this on datastore or it is buildable by their ID but you would still need some sort of way to know what other client_id is for example:
Create a room:
room = models.Room(user=user_id)
room.put()
token = channel.create_channel(room.key.id() + user_id)
Other one joins the room:
room = models.Room.query().get()
room.another_user = user_id
room.put()
token = channel.create_channel(room.key.id() + user_id)
Then pass room id and token for reference on your js to send message:
room = models.Room.get_by_id(room_id)
send_to = room.user if room.user != user_id else room.other_user
channel.send_message(room.key.id() + send_to, message)
Note that user_id on each sample is currently connected user.

Resources