Cannot delete empty SQL Server Broker Queues - sql-server

I have queues created in proper order like so:
CREATE MESSAGE TYPE MyMessageType AUTHORIZATION dbo VALIDATION = WELL_FORMED_XML
GO
CREATE CONTRACT MyMessageContract AUTHORIZATION [dbo] (MyMessageType SENT BY INITIATOR)
GO
CREATE QUEUE [dbo].[MyMessageQueue] WITH STATUS = ON , RETENTION = OFF
GO
CREATE SERVICE [MyMessageService] ON QUEUE [dbo].[MyMessageQueue] (MyMessageContract)
The issue I'm having is when I try delete them all. I start with dropping the service first or contract first or any other one at first, it doesn't matter, I cannot delete.
Any tips?
Please note that the the queue is EMPTY..
Thanks!

It turned out to be a patching issues. We applied all the latest patches and the issue disappeared.

Related

SQLWatch - notifications not being sent

I’m wondering if someone with knowledge/experience of SQLWatch could help me out with something.
We have SQLWatch set up on 2 DEV servers and 1 Central monitoring server, its working fine and the data from the 2 DEV servers is coming over to the central server, I can see alerts are being recorded in the table - [dbo].[sqlwatch_logger_check].
However, our issue that we are not being notified by any means (email, Powershell script running).
What’s interesting is that if we drop a row into the table [dbo].[sqlwatch_meta_action_queue] then alert notification does happen.
So our issue seems to be for some reason alerts are being raised but the record is not being inserted into the queue table. I suspect some sort of mapping issue but as it stands now it all looks ok, I use the following to check
SELECT C.check_id,check_name,check_description,check_enabled,A.action_description,A.action_exec_type,A.action_exec
FROM [dbo].[sqlwatch_config_check] C
LEFT JOIN [dbo].[sqlwatch_config_check_action] CA ON C.check_id = CA.check_id
LEFT JOIN [dbo].[sqlwatch_config_action] A ON CA.action_id = A.action_id
WHERe C.check_id = -1
And it shows the failed job is set to run our PowerShell script, which it does when the row is manually inserted.
Any ideas on what the cause may be here?
Thanks,
Nic
I am the creator of SQLWATCH.
Firstly, just to clarify, default notifications that come with SQLWATCH only work in a local scope i.e. they will happen on each monitored instance where ##SERVERNAME = sql_instance. If you are expecting the default notifications to fire from the central server for a remote instance this will not happen. The default notifications on the central server will only fire for the central server itself and not for data imported from the remote instances. This is done to avoid a situation where pull into the central repository is rare and thus notifications could be well delayed.
However, there is nothing stopping you from creating Check Rules or Reports to fire on the back of the imported data.
Secondly, the checks are not alerts per se. Checks are just... well, checks... that run periodically and make sure everything is in order. Checks can trigger an action to send an email. For this, as you have worked out, there is an association table that links together checks and actions.
As for your problem, is the actual action enabled? All actions that are not associated with report are disabled by default as they need to be configured first:
Add a column to your query to bring action_enabled column:
SELECT C.check_id, check_name, check_description, check_enabled, A.action_description, A.action_exec_type, A.action_exec, [action_enabled]
FROM [dbo].[sqlwatch_config_check] C
LEFT JOIN [dbo].[sqlwatch_config_check_action] CA ON C.check_id = CA.check_id
LEFT JOIN [dbo].[sqlwatch_config_action] A ON CA.action_id = A.action_id
WHERE C.check_id = -1
Or, there is already a view that should provide you with the complete mapping:
SELECT *
FROM [dbo].[vw_sqlwatch_report_config_check_action]
WHERE check_id = -1
The application log table [dbo].[sqlwatch_app_log] should also contain valuable information. Did you look in there for anything out of ordinary?
Summarising
In order to enable alerts in a brand new install of SQLWATCH, all it's needed is setting up action_exec with your email details and action_enabled set to 1. If you have made some other changes it may be easier to reinstall back to default.

Service Broker message flow

I have two different servers in two locations. I need to use asynchronous exchange of data.
Server A is our data server, we store customer info here.
Server B is our proccesing server, we process production.
Each production operation on server B has a production group. What I need to do is:
A to send a message to B with a question: What operations are planned for today in this group(GUID).
B has to answer with an XML list of operations scheduled for today.
A has to answer with an XML list of operations to cancel
B has to cancel operations and end conversation
My question is: What is the right way to go about this? Can I do this in just a single dialog using one contract? Should I?
With a contract like this:
CREATE CONTRACT [GetScheduledContract]
AUTHORIZATION [xxx]
(GetScheduledOutCalls SENT BY INITIATOR,
ReturnScheduledOutCalls SENT BY TARGET,
DeleteScheduledOutCalls SENT BY INITIATOR)
Or should I separate the tasks to different contracts and dialogs?
What you have seems good to me as an MVP (i.e. if things go right, it'll work). A couple of things:
Consider adding one more reply from the target saying "operation completed successfully" before closing the conversation. Upon receipt, the initiator can also close their end of it.
What happens if any of those operations is explicitly not able to be completed (e.g. in your step 4, the request is to delete something that's not present or that delete causes a foreign key violation)? I'd add in some sort of error message type (sent by any) that allows either side to tell the other "hey… something went wrong".
What happens if any of those operations is implicitly not able to be completed (e.g. the message never gets delivered)? The other side may not respond for some reason. Build in some way to at least detect and alert on that.

About multiple conversations and/or queues

I'm wondering about the exact definition of a conversation and MS docs and tutorials are not quite on point with this.
First... is there a difference between a dialog and a conversation ?
Assuming a queue should only contain identical messages or equivalent messages (I.E. message types being handled by an activated procedures in a way similar to a CASE WHEN / SWITCH scenario)
Does each conversation revolve around a unique queue?
If a procedure A sends a message to a queue activating a procedure B which handle the message then emits an answer, can procedure A wait for the answer or should I use a procedure C? Am I right to assume that I must create two queues operating on the same contract? But how many services? In that scenario how and where would I use END CONVERSATION?
If a procedure A sends a message to a queue activating a procedure B which handle the message then emits another/several messages(s) for another/some other procedure(s) C, are all those queues/services / etc. on the same conversation? The same conversation group? (what would I do after the GET CONVERSATION GROUP to ensure my conversations are in the same group?) Does that imply passing the same conversation handle when issuing BEGIN TRANSACTION / BEGIN DIALOG or using
[ WITH
[ { RELATED_CONVERSATION = related_conversation_handle
| RELATED_CONVERSATION_GROUP = related_conversation_group_id } ]
? And... last but not least, If I'm using multiple messages to parallel/fork calls to C with different parameters, in which case would I want to start totally different conversations/conversations groups doing the same thing or is it always better to have a unique "narration"
Oh... another thing... is there a best practice to use several messages to call some treatments then wait for every one of them to finish before starting another one? Is there a way in which each procedure would receive a message, send an answer, and then the procedure activated by the answers could check/count the previous messages in its queue and go on only if they are all there? Would that need to check the conversation id (or conversation group id) to be sure those messages are all emitted by the same group of answers?
I hope that's not too much confusing but MS tutorials are... well... a bit simplistic.
First, a dialog is the same as a conversation as far as I can tell. Two names for the same thing.
Queues can contain many different message types. It's up to the the thing processing the messages (whether that's an internally activated stored procedure or an external application) to discriminate on the type and do the "right thing" with it. A service can have only one queue, but a queue can have many services (though I haven't actually seen that in practice). A service defines what message types is can both accept and produce through the service contract.
In regards to your question about whether you want a queue processor to respond on the same conversation or start a new one is completely up to you. My suggestion would be to respond on the same conversation unless you know that you have a good reason not to. As to how to use the same conversation, you can get the conversation handle when you issue the receive statement. Use that as the conversation handle when you issue the subsequent send with your reply.
The way I think about conversation groups is you may need to talk to different services in regards to the same thing. Here's a contrived example:
Let's say that I have a new hire process. It has the following steps:
Create a login
Create an entry in the payroll system
Register them with your insurance provider
They're all logically for the same event though (i.e. "I hired a new employee"). So, you could bundle all of the conversations in one conversation group and keep track of the individual conversations separately. Something like this:
declare #handle uniqueidentifier, #group uniqueidentifier = NEWID(),
#message XML = '<employee name="Ben Thul" />';
BEGIN TRAN
begin dialog #handle
from service [EmployeeService]
to service 'LoginService'
on contract [LoginContract]
with related_conversation_group = #group;
SEND ON CONVERSATION (#handle)
MESSAGE TYPE [NewLoginRequest]
(#message);
INSERT INTO [dbo].[OpenRequests]
(
[GroupIdentifier],
[ConversationIdentifier],
[ServiceName],
[Status],
[date_modified]
)
VALUES
(#group, #handle, 'LoginService', 'RequestSent', GETUTCDATE());
BEGIN DIALOG #handle
FROM SERVICE [EmployeeService]
TO SERVICE 'PayrollService'
ON CONTRACT [PayrollContract]
WITH RELATED_CONVERSATION_GROUP = #group;
SEND ON CONVERSATION (#handle)
MESSAGE TYPE [NewPayrollRequest]
(#message);
INSERT INTO [dbo].[OpenRequests]
(
[GroupIdentifier],
[ConversationIdentifier],
[ServiceName],
[Status],
[date_modified]
)
VALUES
(#group, #handle, 'PayrollService', 'RequestSent', GETUTCDATE());
BEGIN DIALOG #handle
FROM SERVICE [EmployeeService]
TO SERVICE 'InsuranceService'
ON CONTRACT [InsuranceContract]
WITH RELATED_CONVERSATION_GROUP = #group;
SEND ON CONVERSATION (#handle)
MESSAGE TYPE [NewInsuranceRequest]
(#message);
INSERT INTO [dbo].[OpenRequests]
(
[GroupIdentifier],
[ConversationIdentifier],
[ServiceName],
[Status],
[date_modified]
)
VALUES
(#group, #handle, 'InsuranceService', 'RequestSent', GETUTCDATE());
COMMIT
Now, you have a way to track each of those requests separately and a way to tie them all to the same logical operation. As each service processes the message, it will respond back with either a success, failure, or "I need something else" message. At which point you can update the OpenRequests table with the current status.
Service broker can be overwhelming. My advice for you is to think about what messages need to be passed from where to where and start designing services, message types, contracts, etc around that. It's unlikely that you're going to use all of the functionality that SB has to offer.

SQL Server Service Broker Queue Conversation Group Id

I create a UniqueIdentifier variable #GroupId and assign it a value. I begin DIALOG WITH RELATED_CONVERSATION_GROUP = #GroupId.
When I look in the queue, the conversation_group_id does not match #GroupId. I am trying to send on conversation using a known group conversation Id so I can later RECEIVE TOP(1) WHERE conversation_group_id = #GroupId.
Any suggestions? Nothing I try seems to work.
Thanks,
Brandon
In Service Broker, you don't create the conversation handles, it does. When you issue the begin dialog statement, think of the #dialog_handle variable as an output variable. If you need to add related conversation later, you'll need to store that value (or otherwise be able to determine) for later use.
Out of curiosity, it seems like you're just getting going with Service Broker. I've been using it for a while and never had a need for "related conversations". What are you trying to do?

SQL Server Replication : Removing broken subscriptions at the publisher

We have multiple subscriptions (merge pull) at our subscriber for only 1 "real" subscription. I think we actually broke it like this by adding and removing the subscription from the subscriber side, and then trying to replicate it... multiple times.
Now the problem is not that the replication does not work, I'm pretty confident that I the answer for that. The problem is that I can't drop/delete the broken subscriptions at the subscriber anymore. It just does not work.
When trying to run sp_dropmergepullsubscription at the publisher, it tells me "No subscription is on this publication article".
When trying to run sp_dropsubscription at the publisher, it tells me "This database is not enabled for subscription"
Yes I've checked that I was running all these scripts on the correct database and all that.
Has anybody had a problem like this before ?
Do I need to re-do the publication and the subscription ?
Thanks guys and gals ! :)
Try the following on the publisher:
EXEC sp_dropmergesubscription
#publication = '<publicationName>',
#subscriber = '<subscriberName>',
#subscriber_db = '<dbName>;
GO
delete sysmergesubscriptions where subscriber_server = '<subscriberName>'
use distribution
go
delete msmerge_Agents where subscriber_name = '<subscriberName>'
delete msmerge_subscriptions where subscriber = '<subscriberName>'
...then try setting the pull subscription back up

Resources