In response to the arrival of this new message, Service Broker executes a stored procedure associated with a catalog maintenance service for XCatMgmt, known as its service program.. You
Trang 1Designing a Sample System
The sample messaging system used in this chapter has the following design: an update
stored procedure in AdventureWorks2008.Production.ProductModelstarts up a service
that initiates a conversation with a service in XCatMgmt It does this by sending a message
to the inbound work queue of XCatMgmt When the transaction surrounding the initial
send is complete, Service Broker transmits the message, signaling that a catalog change for
an AdventureWorks Cycles product model is ready for processing
In response to the arrival of this new message, Service Broker executes a stored procedure
associated with a catalog maintenance service for XCatMgmt, known as its service program
This process is known as internal activation; it is internal because the stored procedure
resides in and is activated by SQL Server
Because a Service Broker program might not always be a stored procedure, external
activa-tion is also available when you use event notificaactiva-tion with the QUEUE_ACTIVATIONevent
You can create an event notification service and map it to your Service Broker service and
queue by using syntax such as the following:
CREATE QUEUE NotificationQueue
GO
CREATE SERVICE EventNotificationService
ON QUEUE NotificationQueue
([http://schemas.microsoft.com/SQL/Notifications/PostEventNotification])
GO
CREATE EVENT NOTIFICATION NotifyMe
ON QUEUE NotificationQueue FOR QUEUE_ACTIVATION
TO SERVICE ‘EventNotificationService’, ‘broker-instance-guid’
Note that you need to retrieve your database’s Service Broker unique identifier and
replace’broker-instance-guid’with it for the example to work To do this, you run the
following query:
SELECT service_broker_guid
FROM sys.databases
WHERE NAME = ‘AdventureWorks2008’
go
service_broker_guid
-3036906E-8B9E-4266-A8C6-DD4E01B656CA
(1 row(s) affected)
You should keep this query in mind because you need it later in this chapter when you’re
working on service conversations
Let’s return to the sample system’s description When the catalog maintenance service’s
work is done, it sends an acknowledgment message back to the sender’s inbound queue
Trang 2Service Broker Application
Conversion Group
Dialog (Conversion)
Contract Activation Activation
Service
FIGURE 49.1 Service Broker concepts illustrated
To accomplish everything included in the design so far, you need to represent the
follow-ing kinds of objects in the system:
Two types of messages: one defining product model catalog changes and one for
acknowledgments
Two queues, one for each service
One contract that defines the message flow between the services
Two services, each representing an endpoint in the system
At least one conversation and its related conversation group
The following sections describe how to define and build on all these new constructs, and
you learn how they work together in the orchestration of Service Broker applications
Understanding Service Broker Constructs
To introduce the new Service Broker constructs you’ll be using, Figure 49.1 shows the
interrelations between the constructs described in the upcoming subsections
Figure 49.1 illustrates the fact that a dialog is a conversation between two services These
services exchange typed (or untyped) messages by sending them to queues according to
the rules of a contract Each service can have a service program activated by Service Broker
to receive messages from a queue Every conversation belongs to a conversation group
Messages are always sent with respect to a conversation group One or more conversation
groups make up a Service Broker application
Defining Messages and Choosing a Message Type
For the AdventureWorks2008database to communicate with the XCatMgmtdatabase via
Service Broker, a dialog between two services must take place Within this conversation,
each service sends messages to or receives messages from queues, providing the indirection
needed for the underlying systems to stay loosely coupled
Trang 3The dialog messages are typed to constrain and (optionally) validate their content You use
the new SQL Server database object MESSAGEto represent a typed message Defining the
messages to be transmitted is the first step in building a Service Broker application
You create SQL Server messages by using the following syntax:
CREATE MESSAGE TYPE [ AUTHORIZATION UserName ]
[ VALIDATION = {
NONE | EMPTY | WELL_FORMED_XML |
VALID_XML WITH SCHEMA COLLECTION XMLSchemaCollectionName
} ]
You can alter message types by using the intuitive ALTER MESSAGE TYPEsyntax Before you
create the first message type, you need to create a Windows user on the local server and
associate a SQL Server login with it, giving it db_ownerpermissions in both
AdventureWorks2008andXCatMgmt You need to specify this user in the AUTHORIZATION
clause of any object you create that includes this clause In the examples in this chapter,
this is exemplified as SSBTestUserName
Messages can be validated based on the following options:
NONE—Do no validation; any message content is acceptable
EMPTY—Transmitted messages must be empty
WELL_FORMED_XML—Transmitted messages must be any well-formed XML
VALID_XML WITH SCHEMA COLLECTION—Transmitted messages must be valid XML
cor-responding to any schema in the XML schema collection specified in
XMLSchemaCollectionName.
It is highly recommended that applications use either WELL_FORMED_XMLorVALID_XML
WITH SCHEMA COLLECTION You don’t want just any old message structure coming across
the pipe because your application will almost certainly be looking for specific values in a
specific location XML is appropriate because it is the ubiquitous standard today Note that
the XML content of messages is actually stored as varbinary(MAX) (XML schema
collec-tions are covered in the section “Using XML Schema Colleccollec-tions” in Chapter 47, “Using
XML in SQL Server 2008.”)
Now you should go ahead and create your two message types, both of which should be set
toVALID_XML The first deals with catalog entries and/or changes (that is, updates and
deletions), and the second is a generic message type you use for all acknowledgments
Listing 49.2 shows the schemas for these message types, along with the necessary schema
collection and message type creation syntax
LISTING 49.2 DDL for Creating the Sample Message Types and Their Associated XML
Schema Collections
Note:
Execute the T-SQL below, and then change the USE statement
to ‘USE AdventureWorks2008’ and execute it again.
Trang 4USE XCatMgmt
GO
CREATE XML SCHEMA COLLECTION CatalogChangeSchema
AS
‘<?xml version=”1.0”?>
<xs:schema
targetNamespace=”urn:www-samspublishing-com:examples:ssb:catalogchange”
elementFormDefault=”qualified”
xmlns=”urn:www-samspublishing-com:examples:ssb:catalogchange”
xmlns:xs=”http://www.w3.org/2001/XMLSchema”>
<xs:element name=”CatalogChangeMessage”>
<xs:complexType>
<xs:sequence maxOccurs=”unbounded”>
<xs:element name=”CatalogChange” type=”CatalogChangeType”/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name=”CatalogChangeType”>
<xs:sequence>
<xs:element name=”Summary” type=”xs:string”/>
<xs:element name=”Features” type=”xs:string” minOccurs=”0”/>
<xs:element name=”Specifications” type=”xs:string” minOccurs=”0”/>
</xs:sequence>
<xs:attribute name=”SourceProductId” type=”xs:integer” use=”required”/>
<xs:attribute name=”ManufacturerId” type=”xs:integer” use=”required”/>
<xs:attribute name=”ChangeType”>
<xs:simpleType>
<xs:restriction base=”xs:integer”>
<xs:enumeration id=”Insert” value=”1”/>
<xs:enumeration id=”Update” value=”2”/>
<xs:enumeration id=”Delete” value=”3”/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
<xs:attribute name=”Price” type=”xs:decimal”/>
<xs:attribute name=”Name” type=”xs:string”/>
</xs:complexType>
</xs:schema>’
GO
CREATE MESSAGE TYPE
[//samspublishing.com/SS2008/SSB/MessageTypes/CatalogChangeMessage]
AUTHORIZATION [SSBTestUserName]
VALIDATION = VALID_XML
WITH SCHEMA COLLECTION CatalogChangeSchema
Trang 5GO
CREATE XML SCHEMA COLLECTION GenericAcknowledgementSchema
AS
‘<?xml version=”1.0” encoding=”utf-8” ?>
<xs:schema
targetNamespace=”urn:www-samspublishing-com:examples:ssb:genericack”
elementFormDefault=”qualified”
xmlns=”urn:www-samspublishing-com:examples:ssb:genericack”
xmlns:xs=”http://www.w3.org/2001/XMLSchema”>
<xs:simpleType name=”MsgTypeType”>
<xs:restriction base=”xs:integer”>
<xs:enumeration id=”SuccessMsg” value=”0”/>
<xs:enumeration id=”FailureMsg” value=”1”/>
<xs:enumeration id=”WarningMsg” value=”2”/>
</xs:restriction>
</xs:simpleType>
<xs:element name=”Ack”>
<xs:complexType>
<xs:sequence>
<xs:element name=”ResultMessage”>
<xs:complexType mixed=”true”>
<xs:attribute name=”ContentId”
type=”xs:integer”
use=”optional”/>
<xs:attribute name=”MsgType”
type=”MsgTypeType”/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name=”ResultCode”>
<xs:simpleType>
<xs:restriction base=”xs:integer”>
<xs:enumeration id=”Success” value=”1”/>
<xs:enumeration id=”Failure” value=”0”/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>’
GO
CREATE MESSAGE TYPE
Trang 6[//samspublishing.com/SS2008/SSB/MessageTypes/GenericAck]
AUTHORIZATION [SSBTestUserName]
VALIDATION = VALID_XML
WITH SCHEMA COLLECTION GenericAcknowledgementSchema
Note that the message types and schema collections should be created (as the Listing 49.2
comment indicates) in both participating databases, AdventureWorks2008andXCatMgmt.
The reason is that when you create the XML messages, you might want to temporarily
store them as local typed XML variables to ensure that they are validated before being
sent However, it is only necessary to create the schema collections on the database where
the message will be received because the receiving instance of Service Broker performs the
validation
In theMESSAGE TYPEDDL, you should use this standard naming convention for Service
Broker objects://DomainName/Path/ObjectType/ObjectName This convention will help
you identify your objects later (Don’t worry if the name is long; you can use Object
Explorer’s drag-and-drop feature to drag the name into your scripts.) If you’re curious, you
can view the newly created objects in Object Explorer by selecting theService Broker
node and then expanding theMessage Typesnode You can find the XML schema
collec-tions by selecting theProgrammabilitynode and then selecting theTypesnode and
expanding theXML Schema Collectionsnode
Note that there are several built-in message types that any queue can receive from Service
Broker Service programs should be built to handle these as well as the specific message
types defined in their contracts You can view them all in the Object Brower (they all begin
with http://schemas.microsoft.com/SQL/ServiceBroker/) When receiving messages from a
queue, you should filter them based on themessage_type_namecolumn of the queue to be
sure you handle each one correctly You can expect to see these types in your queues:
Error—This type is enqueued by Service Broker whenever an error is encountered
Alternatively, a user program can choose to create these types
EndDialog—This type is enqueued by Service Broker when a conversation ends in
response to calls toEND CONVERSATION(as explained later in this chapter)
Service programs can also send messages of the built-in type DialogTimer Service Broker
delivers these messages to the specified queue when a specific time period has elapsed To
tell Service Broker to send a DialogTimermessage to the queue associated with a service
after 5 minutes has elapsed, for example, you execute the following T-SQL during a
conversation in the service program:
BEGIN CONVERSATION TIMER (@ConversationHandle) TIMEOUT = 600
In this code, you replace @ConversationHandlewith the unique identifier assigned to your
conversation (as explained later in this chapter)
Now that all your message types are in place and you know which built-in messages to
expect, you can create the contract that defines the message flow in this system
Trang 7Setting Up Contracts for Communication
You use contracts to specify which messages can flow from which endpoints to which
queues Two new T-SQL keywords come into play here:
INITIATOR—This service begins a messaging conversion
TARGET—This service engages in (or accepts) conversions with an initiator
As described earlier, the sample system is initiated by a stored procedure in
AdventureWorks2008that sends a message of type CatalogChangeMessageto a queue in
XCatMgmt Every CatalogChangeMessageis thus sent by a conversation initiator
The catalog management service that receives these messages sends an acknowledgment
reply message of type GeneralAckwhen it completes the requested change GeneralAck
messages in this case are thus sent by the target of the original initiated message
To create the contract that represents this message flow, you need to execute the following
code in both databases:
Note: Change SSBTestUserName to a user on your system,
and run this code on both AdventureWorks2008 and XCatMgmt
CREATE CONTRACT
[//samspublishing.com/SS2008/SSB/Contracts/BasicCatalogChangeContract]
AUTHORIZATION [SSBTestUserName]
(
[//samspublishing.com/SS2008/SSB/MessageTypes/CatalogChangeMessage]
SENT BY INITIATOR,
[//samspublishing.com/SS2008/SSB/MessageTypes/GenericAck]
SENT BY TARGET
)
This code for creating contracts also allows for message types to be sent by either the
initiator or the target, in which case, you need to specify SENT BY ANY A service can also
be bound to more than one contract Note that there is also a built-in contract called
DEFAULT(as well as a message type of DEFAULT) that you use during conversations that do
not specify a contract
Contracts cannot be altered because only DROP CONTRACTexists
Now that your contract and message types are ready, the next step is to create the queues
needed to store the messages
Creating Queues for Message Storage
Queues represent a layer of communication indirection between services, allowing them
to send and receive messages independently of each other A queue is a first-class database
object, internally implemented as a table that has some unique behaviors
Trang 8NOTE
You can select values from any queue by using standard syntax, such as SELECT *
FROM QueueName WITH (NOLOCK) This has no effect on the data in the queue, nor
does it imply a message receive operation It does, however, cause blocking on the
internal queue table, so you should always use the NOLOCKhint Data Manipulation
Language (DML) statements on queues are not permitted
The following is the syntax for creating a queue:
CREATE QUEUE DatabaseName.SchemaName.QueueName
[ WITH
[ STATUS = { ON | OFF } [ , ] ]
[ RETENTION = { ON | OFF } [ , ] ]
[ ACTIVATION (
[ STATUS = { ON | OFF }, ]
PROCEDURE_NAME = SPName,
MAX_QUEUE_READERS = Number,
EXECUTE AS { SELF | ‘UserName’ | OWNER }
) ]
]
[ ON { filegroup | [ DEFAULT ] } ]
This syntax contains the following options:
STATUS—This option turns the queue on or off, meaning that it may or may not be
used (This capability is useful with ALTER QUEUEwhen a queue must be temporarily
put offline.) It defaults to ON
RETENTION—This option turns message retention on or off during active conversations
that use the queue It defaults toOFF You might need to turn this feature on at some
point if you need to see messages that have already been processed The reason is that
the normal message receive operation implicitly deletes a message when the
transac-tion that surrounds it commits WhenRETENTIONis set toON, the value in the status
column for the queue is changed to1after a receive instead of a deletion In addition,
sent messages are copied to the sender’s queue (duplicated) and given astatusvalue
of3, to fully audit the message flow in both directions.
ACTIVATION—This clause is used to specify the following options regarding the
inter-nally activated stored procedure (described earlier):
STATUS—This option is used to turn activation on or off (You may want to
temporarily turn off activation when updating a procedure.) It defaults toON.
PROCEDURE_NAME—This option specifies the name of the activated procedure
Trang 9MAX_QUEUE_READERS—This option supplies an integer that indicates to Service
Broker the maximum number of instances of the activated procedure to create
This setting hints at the fact that Service Broker uses multithreading to
instan-tiate additional queue readers when unread messages in the queue build up
faster than the existing instances can process them This is a great boon to
developers because they no longer have to develop and maintain the
multi-threaded code to perform this task To do this, Service Broker internally creates
queue monitors that keep an eye on the number of unread messages in the
queue Keep this number the same as the number of processor cores you have
in your system
EXECUTE AS—This option specifies the name of the user under which the
initi-ated procedure runs
You need two queues for the application so far: one used by each service The T-SQL in
Listing 49.3 creates them
LISTING 49.3 T-SQL for Creating Queues and Their Activated Stored Procedures
USE XCatMgmt
GO
CREATE PROC Publication.CatalogChangeQueueReader
AS
GO
CREATE QUEUE Publication.CatalogChangeQueue
WITH
STATUS = ON,
ACTIVATION
(
STATUS = ON,
PROCEDURE_NAME = Publication.CatalogChangeQueueReader,
MAX_QUEUE_READERS = 10,
EXECUTE AS ‘SSBTestUserName’
)
GO
USE AdventureWorks2008
GO
CREATE PROC Production.CatalogChangeAckQueueReader
AS
GO
CREATE QUEUE Production.CatalogChangeAckQueue
WITH
STATUS = ON,
ACTIVATION
(
STATUS = ON,
PROCEDURE_NAME = Production.CatalogChangeAckQueueReader,
Trang 10MAX_QUEUE_READERS = 10,
EXECUTE AS ‘SSBTestUserName’
)
The code in Listing 49.3 declares an empty stored procedure for each queue You can fill
this shell after you define the services
Defining Services to Send and Receive Messages
Services represent the endpoints in Service Broker applications You can think of them as
the glue that binds contracts with queues This binding ensures that the typed messages
specified in the contract end up in the appropriate queues
Here is the DDL syntax for creating services:
CREATE SERVICE ServiceName
[AUTHORIZATION OwnerName]
ON QUEUE [SchemaName.]QueueName
[( ContractName | [ DEFAULT ] [ , n ] )] [;]
For this example, you need to create two services: the initiator in AdventureWorks2008and
the target in XCatMgmt
This is the initiator in AdventureWorks2008:
USE AdventureWorks2008
GO
CREATE SERVICE
[//samspublishing.com/SS2008/SSB/Services/CatalogChangeInitiatorService]
AUTHORIZATION [SSBTestUserName]
ON QUEUE
Production.CatalogChangeAckQueue
([//samspublishing.com/SS2008/SSB/Contracts/BasicCatalogChangeContract])
And this is the target in XCatMgmt:
USE XCatMgmt
GO
CREATE SERVICE
[//samspublishing.com/SS2008/SSB/Services/CatalogMaintenanceService]
AUTHORIZATION [SSBTestUserName]
ON QUEUE
Publication.CatalogChangeQueue
([//samspublishing.com/SS2008/SSB/Contracts/BasicCatalogChangeContract])
As you can see, creating services is simple Now that all the plumbing is in place, you can
begin the dialog between the services