views:

25

answers:

2

There's an app that starts a transaction on SQL Server 2008 and moves some data around. Then, while the transaction is still not committed, the app prints out some labels. It is very important that the transaction is not committed until printing succeeded; if a printing error occurs, everything is rolled back.

Now, the printing engine is a) grew quite huge and complex, and b) is eventually required from lots of places. It is therefore decided to separate the engine and make it a service.

Yes, it is possible to pass all data required for printing from the client app to that server so that the server only prints and is not concerned about databases. However, that would mean leaving piles of code and label templates in each application that requires printing; effectively, very little separation will then occur. On contrary, it would be extreemely efficient (and easier for me to write and maintain) to just pass the IDs of what is required to the service which then would go to the database and get the data. All formats and layouts will be centralized and apps will only ask for 5 delivery notes from print job 12345.

Now, this is not going to happen as the transaction is still not committed at the moment of printing. The service would not be able to read the data, and using READ UNCOMMITTED is not quite an option.

I was going to use the good old sp_bindsession to join the two sessions, app's and service's, but then it is suddenly deprecated and to be removed from future releases. The help suggests I use MARS or distributed transactions instead, but I can't see how they would help.

Any advice?

A: 

Only sp_getbindtoken/sp_bindsession can do what you ask, and it is deprecated and will be removed.

In theory you should use short transactions, represent the 'printing' state as a committed state, and have compensating actions if the print fails. Also if the printing engine is exposed as a service, it should be autonomous and receive as a message all data it needs to print (like label templates). I understand this is easy for me to to say but may be a major undertaking on the product.

For the moment I think your best bet is to use the session binding tokens. Altough I have to call out that leaving transactions open for the duration of physical operations (printing) is a very bad practice.

Remus Rusanu
The point is, different apps want to use same labels, and at the moment each app has its own copy and it's no good as I have to go and update each app when layout changes. Printing takes basically no time as it's done in printer language, not GDI. Printer eats the data in no time after which the job considered to be done. And I'd rather not do a would-be-commit as other programs then will feel themselves free to make further decisions based on the recent commit, and now we're coming to a custom locking system which I'm quite reluctant to. So sp_bindsession, I suppose :(.
GSerg
A: 

My gut feeling is that attempting to share a transaction between two processes in this way is not a good idea.

My approach would be to either to pass all data to service, or investigate alternatives to keeping the transaction open for the duration of the printing - would a simpler mechanism (such as an IsPrinted flag for each record) not suffice?

Failing that, the eaisest way I can see of doing this would be to have the printing service pass all of its SQL requests back through to the originating process so that they can be executed in the context of the original transaction.

Kragen
Rigth.After having some thoughs, we decided to not use any depecated functionality.It was decided that each label format globally defined by the printing service will have a corresponding stored sql function that will return XML with label parameters for given printjob. Caller app will execute the function in its context and pass resulting XML as a string to the printing service. It's basically what you suggested but tidied up a bit.
GSerg