2010-04-23 6 views
1

Je construis un système utilisant NServiceBus et mon DataLayer utilise Linq 2 SQL.linq to sql avec verrou de table nservicebus problème

Le système est composé de 2 services.

Service1 reçoit des messages de NSB. Il interrogera Table1 dans ma base de données et insère un enregistrement dans Table1 Si une certaine condition est remplie d'un nouveau message NSB est envoyé au 2ème service

Service2 mettra à jour les dossiers aussi au tableau 1 lorsqu'il reçoit des messages de service1 et il fait un autre travail non lié à la base de données. Service2 est un processus de longue durée.

Le problème que je rencontre est le moment où Service2 met à jour un enregistrement dans le tableau 1, la table est verrouillée. Le verrou semble être en place jusqu'à ce que Service2 ait terminé tout ce qu'il est en train de traiter. c'est-à-dire que le verrou n'est pas libéré après que mon datacontext ait été éliminé.

Cela provoque l'expiration de la requête dans Service1. Une fois que Service2 a terminé le traitement, Service1 reprend le traitement sans problème.

Ainsi, par exemple le code Service1 peut ressembler à:

int x =0; 
using (DataContext db = new DataContext()) 
{ 
    x = (from dp in db.Table1 select dp).Count(); // this line will timeout while service2 is processing 

    Table1 t = new Table1(); 
    t.Data = "test"; 
    db.Table1.InsertOnSubmit(t); 
    db.SubmitChanges(); 
} 

if(x % 50 == 0) 
    CallService2(); 

Le code service2 peut ressembler à:

using (DataContext db = new DataContext()) 
{ 
    Table1 t = db.Table1.Where(t => t.id == myId); 
    t.Data = "updated"; 

    db.SubmitChanges(); 

} 

// I would have expected the lock to have been released at this point, but this is not the case. 

DoSomeLongRunningTasks(); 

// lock will be released once service2 exits 

Je ne comprends pas pourquoi le verrou est pas libéré lorsque le DataContext est disposé dans Service2.

Pour contourner le problème que j'ai appelé:

db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED"); 

et cela fonctionne, mais je ne suis pas content de l'utiliser. Je veux résoudre ce problème correctement.

Quelqu'un at-il déjà connu ce genre de problème et sait-on comment le résoudre? Pourquoi le verrou n'est-il pas libéré après le retrait du datacontext?

Merci d'avance.

p.s. désolé pour le poste extrêmement long.

EDIT:

regardant cela dans une situation réelle du monde (ish) telles que la navigation:

service1 ajoute des enregistrements de caisse à la base de données. la caisse est ajoutée à un enregistrement de conteneur (s'il n'existe aucun enregistrement de conteneur) si un certain nombre d'enregistrements de caisse ou de caisse existe, puis créez un enregistrement d'expédition et fermez tous les conteneurs et affectez-les à un enregistrement d'expédition. Ensuite, appelez service2 pour traiter l'enregistrement d'expédition.

l'appel à service2 est un appel Bus.Send, mais pourrait faire partie d'une saga. service2 mettrait à jour chaque enregistrement de caisse sur le navire auquel il est affecté. puis d'autres instructions d'expédition sont traitées. pendant le traitement de service2, plus de caisses peuvent être reçues pour la prochaine expédition, mais en l'état, elles ne peuvent pas être affectées aux conteneurs tant que service2 n'a pas terminé le traitement de l'expédition.

Répondre

4

La raison pour laquelle vous voyez ce comportement est que le niveau d'isolation par défaut utilisé par NServiceBus (qui est le même pour TransactionScope) est Serializable - qui verrouille la totalité de la table.

Ce que vous voulez faire est de définir un niveau d'isolation différent au niveau NServiceBus. Pour ce faire, vous devez utiliser l'API d'initialisation fluide et, après l'appel de .MsmqTransport(), appeler la méthode .IsolationLevel (IsolationLevel.ReadCommitted) ou transmettre une autre valeur. Je ne recommande pas d'aller plus bas que cela (comme lire non validés). Dans le scénario décrit ci-dessus, je ne mettrais pas tout cela dans un seul gestionnaire, préférant l'utilisation d'une saga pour gérer le flux de haut niveau, puisque vous semblez assez heureux pour briser les limites d'isolation à mi-chemin de votre gestionnaire .

Espérons que ça aide.

+0

Merci mille fois pour ça. C'est exactement ce dont j'ai besoin. – IGoor

+0

effectivement, en changeant le niveau d'isolation au niveau NSB à readcommitted n'améliore pas les choses. je rencontre toujours le même problème. – IGoor

+1

Ensuite, vous devez examiner les plans d'exécution dans la base de données pour voir s'il vous manque un index qui entraîne des analyses de table complètes, améliorant ainsi le verrouillage. –