Pergunta

Eu ter sido mordido por uma solução mal arquitetado. Não é thread-safe!

Eu tenho várias classes compartilhadas e membros na solução, e durante o desenvolvimento estava tudo legal ...
BizTalk afundou meu navio batalha.

Estamos usando um costume BizTalk Adapter para chamar minhas montagens. O adaptador está chamando meu código e executar as coisas em paralelo, por isso suponho que está usando vários segmentos todos sob o mesmo AppDomain.

O que eu gostaria de fazer é fazer o meu código executado sob seu próprio AppDomain para que os problemas comuns que tenho não vai muck uns com os outros.

Eu tenho uma classe muito simples que o adaptador BizTalk é instanciar em seguida, a execução de um método Process ().

Eu gostaria de criar um novo AppDomain dentro do meu processo de método (), de modo que cada BizTalk tempo gira outro segmento, ele terá sua própria versão das classes e métodos estáticos.

Código BizTalkAdapter:

  // this is inside the BizTalkAdapter and it is calling the Loader class //
  private void SendMessage(IBaseMessage message, TransactionalTransmitProperties properties)
    {

        Stream strm = message.BodyPart.GetOriginalDataStream();
        string connectionString = properties.ConnectionString;
        string msgFileName = message.Context.Read("ReceivedFileName", "http://schemas.microsoft.com/BizTalk/2003/file-properties") as string;


        Loader loader = new Loader(strm, msgFileName, connectionString);
        loader.Process();

        EventLog.WriteEntry("Loader", "Successfully processed: " + msgFileName);

    }

Esta é a classe chama BizTalk:

public class Loader
{

    private string connectionString;
    private string fileName;
    private Stream stream;
    private DataFile dataFile;

    public Loader(Stream stream, string fileName, string connectionString)
    {
        this.connectionString = connectionString;
        this.fileName = fileName;
        this.stream = stream;
    }  

    public void Process()
    {

        //*****  Create AppDomain HERE *****
        // run following code entirely under that domain
        dataFile = new DataFile(aredStream, fileName, connectionString);
        dataFile.ParseFile();
        dataFile.Save();
        // get rid of the AppDomain here...

    }

}

FYI:. A classe Loader está em uma DLL separada da classe arquivo de dados

Qualquer ajuda seria apreciada. Vou continuar a trabalhar para tornar o código thread-safe, mas eu sinto que esta poderia ser a resposta "simples".

Se alguém tiver qualquer outro pensamento, por favor, jogue no.

Obrigado,
Keith

Apenas para ser completo.

Eu achei que se eu marcou o adaptador de envio como "ordenado entrega" em os "Transportes Opções avançadas" diálogo eu era capaz de evitar a questões multi-thread que eu estava tendo.

Eu acho que esta é uma outra possível resposta para o meu problema, mas não necessariamente à pergunta.

Foi útil?

Solução

Usando o aplicativo domínios que você poderia fazer algo parecido com isto:

public class Loader
{

    private string connectionString;
    private string fileName;
    private Stream stream;
    private DataFile dataFile;

    public Loader(Stream stream, string fileName, string connectionString)
    {
        this.connectionString = connectionString;
        this.fileName = fileName;
        this.stream = stream;
    }  

    public void Process()
    {
        //*****  Create AppDomain HERE *****
        string threadID = Thread.CurrentThread.ManagedThreadId.ToString();
        AppDomain appDomain = AppDomain.CreateDomain(threadID);

        DataFile dataFile = 
            (DataFile) appDomain.CreateInstanceAndUnwrap(
                        "<DataFile AssemblyName>", 
                        "DataFile", 
                        true, 
                        BindingFlags.Default,
                        null,
                        new object[] 
                        { 
                            aredstream, 
                            filename, 
                            connectionString 
                        },
                        null,
                        null,
                        null);
        dataFile.ParseFile();
        dataFile.Save();

        appDomain.Unload(threadID);       
    }
}

Outras dicas

O que mordeu, exatamente, está sendo uma dor em termos de segurança do thread? Eu não consigo ver nenhum nem singletons estado estático? - e parece haver apropriadas "novos" objetos ... estou sendo cego

Então, o que é o sintoma que você está vendo ...

Um AppDomain resposta será (relativamente) lento. Como parte de um sistema apoiado pelo middleware isso pode ser OK (ou seja, o "relativamente" está na mesma bola-parque).

Se você do ter algum algum lugar estado estático, outra opção que às vezes funciona é [ThreadStatic] - que interpreta o tempo de execução como "este campo estático é exclusivo por thread". Você precisa ter cuidado com a inicialização, embora - o construtor estático na linha de uma pode atribuir um campo, mas depois enrosque B veria um nulo / 0 / etc

.

Por que não colocar um bloqueio em torno do código que você deseja executar sequencialmente? Vai ser um gargalo, mas deve funcionar em um ambiente multithread.

public class Loader
{
    private static object SyncRoot = new object();
    private string connectionString;
    private string fileName;
    private Stream stream;
    private DataFile dataFile;

    public Loader(Stream stream, string fileName, string connectionString)
    {
        this.connectionString = connectionString;
        this.fileName = fileName;
        this.stream = stream;
    }  

    public void Process()
    {

        lock(SyncRoot) {
            dataFile = new DataFile(aredStream, fileName, connectionString);
            dataFile.ParseFile();
           dataFile.Save();
        }

    }

}

Se você compartilhou estática que são conflitantes entre si, então você pode querer tentar adicionar atributo [ThreadStatic] para eles. Isto irá torná-los local para cada segmento. Isso pode resolver o seu problema no curto prazo. A solução correta seria a de simplesmente rearchitect seu material para ser thread-safe.

Apenas para ser completo.

Eu achei que se eu marcou o adaptador de envio como "ordenado entrega" no "Transporte Opções avançadas" diálogo eu era capaz de evitar os problemas multi-thread que eu estava tendo.

Eu acho que esta é uma outra possível resposta para o meu problema, mas não necessariamente para a questão.

Criando e destruindo um appdomain para cada chamada - Acho que você não está preocupado com o desempenho em um presente

?

Idealmente, você deve alterar o código de chamada a ser threadsafe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top