We are developing an application that will use service broker to transfer messages from one database to another. SourceDB is used by an existing application from which we are siphoning off some data. TargetDB is used only by this application and processes/distributes the data we need. We are only using one type of contract and both DBs are on the same server.
We have set up identical message types and contracts on both, and respective initiator and target queue/service. On both databases:
ENABLE_BROKER is set
TRUSTWORTHY is set
Have a unique service_broker_guid
Have sa as db owner, with all SSB authorization statements are dbo or OWNER, as appropriate.
However, when we send a message from SourceDB:
BEGIN DIALOG CONVERSATION #dialogHandle
FROM SERVICE [//Service/Initiator]
TO SERVICE N'//Service/Target'
ON CONTRACT [//Contract/Notification]
WITH ENCRYPTION = OFF;
SEND ON CONVERSATION #dialogHandle
MESSAGE TYPE [//Message/Notification] (#RequestMsg);
...messages do not find their way there. Further investigation reveals the following:
The initiator queue is empty
The target queue is empty (NB: not an issue of needing to RECEIVE)
The transmission queue is empty
No errors are recorded, either in the SQL Server logs or in our CATCH error handling in the stored procedure that creates the message
The initiator queue's entry in SourceDB's sys.dm_broker_queue_monitors is set to NOTIFIED if activation is enabled
SourceDB's sys.conversation_endpoints has a new entry in CONVERSING state
The target queue's entry in TargetDB's sys.dm_broker_queue_monitors remains INACTIVE if activation is enabled
TargetDB's sys.conversation_endpoints has a new entry in CONVERSING state with the same conversation_id and different conversation_handle from SourceDB's entry
Although the test database is SQL 2005 (application must support 2005), I ran the ssbdiagnose utility from my development machine's 2008 installation to dianose the issue:
ssbdiagnose -S testserver -d SourceDB CONFIGURATION FROM SERVICE //Service/Initiator TO SERVICE //Service/Target ON CONTRACT //Contract/Notification
That produced the following:
D 29912 dbtestsvr SourceDB Service //Service/Target was not found
D 29975 dbtestsvr SourceDB User dbo does not have SEND permission on service //Service/Target
This is confusing, since dbo should not be denied any permission, and //Service/Target certainly does exist, albeit in a different database. But my coworker ran a Profiler trace that showed a command being executed looking for //Service/Target on SourceDB. Service broker seems to be getting confused somehow. Adding an explicit route, in addition to being theoretically unnecessary, does not change the situation.
I ran a nearly-identical set of tutorial commands on our test server and everything worked fine, so it is likely something db-specific.
Our setup was working two days ago, so we're probably looking for some setting that might have gotten changed, but with no luck.
Related
I have a strange one for you. I'm maintaining several databases prior to a migration. One of them is a 2008R2 instance. This instance has multiple errors in the logs (the infrastructure has been poorly maintained), so I set up a bunch of alerts (16-25) and tried using Database Mail to send them. But the mail registry settings keep resetting and preventing it from working. I can't tell if someone is maliciously going in behind me and reverting the settings in the registry (this is possible in the poisonous environment I'm working in) or whether it's some kind of obscure problem.
Just to confirm... I've created the same alerts with the same mail settings on the 2017 instances that I'm also monitoring with no problem. Equally, on the 2008R2 instance, I can successfully set the Database Mail parameters, send myself a test email AND execute a job, sending a 'completed' email using the same Database Mail profile and user via an Operator.
Setting the parameters using xp_instance_regwrite or sp_set_sqlagent_properties didn't work either, although I realised early on that the parameters weren't sticking because of a lack of admin rights on the server, so I got the infrastructure guys to give me access. I then:
logged in to the server
shut down the Agent (it isn't doing anything at all)
configured the registry settings (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10_50.<instance>\SQLServerAgent\UseDatabaseMail = 1, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10_50.<instance>\SQLServerAgent\DatabaseMailProfile = <my-mail-profile>)
restarted the Agent.
I then confirmed from SSMS that the 'Mail session' parameters (Enable mail profile, Mail system and Mail profile) were correctly set. A day later, the log is full of errors, I have no emails and all of the Agent properties are empty and greyed out!
Anyone seen this before?
I am trying to set up a merge replication using web synchronization between a publishing SQL Server 2012 standard and subscribing SQL Server 2012 Express. After following the instructions provided at Technet, I am stuck on this:
Source: Merge Process(Web Sync Server)
Number: -2147200985
Message: The subscription to publication 'MyMergePublication' has expired or does not exist.
I already verified that SSL certification are good, that I can browse to the publishing machine's URL https:\\mycomputer\replisapi.dll and get the expected output. I already verified that snapshot was set up and I took a giant hammer & use an administrator account to run the pool identity which is really bad security-wise but wanted to validate that it was not security that was tripping me up.
To further the mystery, when I try and fail to sync, the publisher acknowledges that a new subscriber has been registered, but it cannot get the snapshot at all and thus subscriber database is still empty.
On the replication monitor, there are no failed synchronization history, or any errors; all it has to say is that the subscriber is uninitialized, and no more.
Turning up the verbosity of the merge agent, I saw some sql being executed and tried replicating the sql and i found this was failing with same error:
{call sys.sp_MSgetreplicainfo(?,?,?,?,?,?,?,90)}
I called it with only the 3 mandatory parameters supplied and it would fail. That is despite the prior call sp_helpmergepublication does return a row for that publication. Oddly, the content of sp_helpmergepublication does not match what I configured for the subscription (e.g. it says web url is null when viewing the properties correctly shows the web url being set). Not sure that is significant.
The content of sp_MSgetreplicainfo contains a call to another system sprocs that I cannot run for some reason (says not found) so I'm not sure what is actually going on here.
Any clues would be greatly appreciated.
I am learning how to use the Service Broker of SQL Server 2008 R2. When following the tutorial Completing a Conversation in a Single Database. Following the Lesson 1, I have successfully created the message types, contract, the queues and services. Following the Lesson 2, I have probably sent the message. However, when trying to receive the message, I get the NULL for the ReceivedRequestMsg instead of the sent content.
When looking at the sys.transmission_queue, the transmission_status for the message says:
An exception occurred while enqueueing a message in the target queue. Error: 15517, State: 1. Cannot execute as the database principal because the principal "dbo" does not exist, this type of principal cannot be impersonated, or you do not have permission.
I have installed SQL Server using the Windows login like Mycomp\Petr. I am using that login also for the lessons.
Can you guess what is the problem? What should I check and or set to make it working?
Edited 2012/07/16: For helping to reproduce the problem, here is what I did. Can you reproduce the error if you follow the next steps?
Firstly, I am using Windows 7 Enterprise SP1, and Microsoft SQL Server 2008 R2, Developer Edition, 64-bit (ver. 10.50.2500.0, Root Directory located at C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQL_PRIKRYL05\MSSQL).
Following the tutorial advice, I have downloaded the AdventureWorks2008R2_Data.mdf sample database, and copied it into C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQL_PRIKRYL05\MSSQL\DATA\AdventureWorks2008R2_Data.mdf
The SQL Server Management Studio had to be launched "As Administrator" to be able to attach the data later. Then I connected the SQL Server.
Right click on Databases, context menu Attach..., button Add..., pointed to AdventureWorks2008R2_Data.mdf + OK. Then selected the AdventureWorks2008R2_Log.ldf from the grid below (reported as Not found) and pressed the Remove... button. After pressing OK, the database was attached and the AdventureWorks2008R2_log.LDF was created automatically.
The following queries were used for looking at "Service Broker enabled/disabled", and for enabling (the Service Broker was enabled successfully for the database):
USE master;
GO
SELECT name, is_broker_enabled FROM sys.databases;
GO
ALTER DATABASE AdventureWorks2008R2
SET ENABLE_BROKER
WITH ROLLBACK IMMEDIATE;
GO
SELECT name, is_broker_enabled FROM sys.databases;
GO
Then, following the tutorial, the queries below were executed to create the message types, the contract, the queues, and the services:
USE AdventureWorks2008R2;
GO
CREATE MESSAGE TYPE
[//AWDB/1DBSample/RequestMessage]
VALIDATION = WELL_FORMED_XML;
CREATE MESSAGE TYPE
[//AWDB/1DBSample/ReplyMessage]
VALIDATION = WELL_FORMED_XML;
GO
CREATE CONTRACT [//AWDB/1DBSample/SampleContract]
([//AWDB/1DBSample/RequestMessage]
SENT BY INITIATOR,
[//AWDB/1DBSample/ReplyMessage]
SENT BY TARGET
);
GO
CREATE QUEUE TargetQueue1DB;
CREATE SERVICE
[//AWDB/1DBSample/TargetService]
ON QUEUE TargetQueue1DB
([//AWDB/1DBSample/SampleContract]);
GO
CREATE QUEUE InitiatorQueue1DB;
CREATE SERVICE
[//AWDB/1DBSample/InitiatorService]
ON QUEUE InitiatorQueue1DB;
GO
So far, so good.
Then the following queries are used to look at the queues (now empty when used):
USE AdventureWorks2008R2;
GO
SELECT * FROM InitiatorQueue1DB WITH (NOLOCK);
SELECT * FROM TargetQueue1DB WITH (NOLOCK);
SELECT * FROM sys.transmission_queue;
GO
The problem manifests when the message is sent:
BEGIN TRANSACTION;
BEGIN DIALOG #InitDlgHandle
FROM SERVICE
[//AWDB/1DBSample/InitiatorService]
TO SERVICE
N'//AWDB/1DBSample/TargetService'
ON CONTRACT
[//AWDB/1DBSample/SampleContract]
WITH
ENCRYPTION = OFF;
SELECT #RequestMsg =
N'<RequestMsg>Message for Target service.</RequestMsg>';
SEND ON CONVERSATION #InitDlgHandle
MESSAGE TYPE
[//AWDB/1DBSample/RequestMessage]
(#RequestMsg);
SELECT #RequestMsg AS SentRequestMsg;
COMMIT TRANSACTION;
GO
When looking at the queues, the Initiator... and the Target... queues are empty, and the sent message can be found in sys.transmission_queue with the above mentioned error reported via the transmission_status.
alter authorization on database::[<your_SSB_DB>] to [sa];
The EXECUTE AS infrastructure requires dbo to map to a valid login. Service Broker uses the EXECUTE AS infrastructure to deliver the messages. A typical scenario that runs into this problem is a corporate laptop when working from home. You log in to the laptop using cached credentials, and you log in into the SQL using the same Windows cached credentials. You issue a CREATE DATABASE and the dbo gets mapped to your corporate domain account. However, the EXECUTE AS infrastructre cannot use the Windows cached accounts, it requires direct connectivity to the Active Directory. The maddening part is that things work fine the next day at office (your laptop is again in the corp network and can access to AD...). You go home in the evening, continue with Lesson 3... and all of the sudden it doesn't work anymore. Make the whole thing seem flimsy and unreliable. Is just the fact that AD conectivity is needed...
Another scenatio that leads to the same problem is caused by the fact that databases reteint the SID of their creator (the Windows login that issues the CREATE DATABASE) when restored or attached. If you used a local account PC1\Fred when you create the DB and then copy/attach the database to PC2, the account is invalid on PC2 (it is scoped to PC1, of course). Again, not much is affected but EXECUTE AS is, and this causes Service Broker to give the error you see.
And last example is when the DB is created by a user that later leaves the company and the AD account gets deleted. Seems like revenge from his part, but he's innocent. The production DB just stops working, simply because it's his SID that the dbo maps too. Fun...
By simply changing the dbo to sa login you fix this whole EXECUTE AS thing and all the moving parts that depend on it (and SSB is probably the biggest dependency) start working.
You would need to grant receive on your target queue to your login. And it should work!
USE [YourDatabase]
GRANT RECEIVE ON [dbo].[YourTargetQueue]
TO [Mycomp\Petr];
GO
And you also need to grant send for your user, permission on Target Service should be sufficient, but let's enable on both services for the future.
USE AdventureWorks2008R2 ;
GO
GRANT SEND ON SERVICE::[//AWDB/1DBSample/InitiatorService]
TO [Mycomp\Petr] ;
GO
GRANT SEND ON SERVICE::[//AWDB/1DBSample/TargetService]
TO [Mycomp\Petr] ;
GO
Have a working Service Broker set up on a server, we're in the process of moving to a new server but I can't seem to get Service Broker set up on the new box.
Have done the obvious (to me) things like Enabling Broker on the DB, dropping the route, services, contract, queues and even message type and re adding them, setting ALTER QUEUE with STATUS ON
SELECT * FROM sys.service_queues
gives me a list of the queues, including my own two, which show as activation_enabled, receive_enabled etc.
Needless to say the queues aren't working. When I drop messages into them nothing goes in and nothing comes out.
Any ideas? I'm sure there's something really obvious I've missed...
Just a shot in the dark:
ALTER AUTHORIZATION ON DATABASE::[restored db name] TO [sa];
The dbo of the restored database is the Windows SID that created the db on the original server. This may be a local SID (eg. SERVERNAME\user) that has no meaning on the new server. This problem usually affects activated procedures and may affect message delivery, both issues happening due to inability of SQL to impersonate 'dbo'. Changing dbo to a valid login SID (like sa) would fix it.
If this doesn't fix it, then you need to track down where do the messages go. If they stay in sys.transmission_queue, then you must check the transmission_status. If they reach the target queueu but no activation occurs, check ERRORLOG. If they vanish, it means you do fire-and-forget (SEND followed immediately by END) and you are therefore deleting the error message that indicates the cause. This article Troubleshooting Dialogs contains more tips where to look.
And last, but not least, try using ssbdiagnose.exe.
In addition to Remus's answer, You might also want to check the BrokerEnabled property of the restoredDB. Whenever you restore a DB, the BrokerEnabled property of the restored DB is set to False. For this reason nothing will go into your queue. To address this:
right click on the restoredDB in SSMS > goto "Properties" > "Options" >
Scroll down to the "Service Broker" group and verify the value of the "Broker
Enabled" property. If it is set to False, change it to True and this
should solve your problem.
I am trying to configure auditing on my SQL Server using Service Broker. I did all the configuration needed to capture the DDL Events (queue, routes, endpoints, event notification). It is working properly except that I am not able to get the hostname of the client from where the DDL event originated from.
Using the service broker's activation procedure, I tried reading the value from the message_body, but there's no xml element that contains the hostname. I can see a value for the SPID but am unable to make use of it. Exec'ing sp_who and querying sys.processes against this SPID doesn't return any value. And running sp_who without parameter shows only one process (I think it's the background process used by the service broker). Is it all because the message was sent asynchronously? But why will it cause the activation context to see different data on sys.processes view?
I am aware that there are DDL triggers that can achieve the same goal, but it seems it is tightly coupled to the command that causes it to fire. So if the triggers fails, the command will also fail.
UPDATE: I managed to retrieve the Hostname by using a combination of xp_cmdshell and sqlcmd (command line app). But I also realized that since the message is asynchronous, it is not always reliable (The SPID who issue the DDL command might have been disconnected already before the message is read from the queue).
I'm not exactly sure what you're trying to implement here, but it's expected that activated procedure will only see a subset of rows in DMVs. This has to do with activation context which often impersonates a different user that you use when debugging the procedure. That impersonated user will only see these rows of server-level views and DMVs to which it has permissions. See here and here for more info.