2015-04-28 10 views
9

Witam Buduję usługę chmurową, która ma (na razie) jedną sieć i jedną rolę pracownika. Pożądany przepływ pracy będzie następujący: przeglądarka wywołuje kontroler webApi w roli internetowej, która wysyła wiadomość do kolejki (lub magistrali usług), która jest następnie przetwarzana przez rolę robota. Jak na razie dobrze. Teraz, gdy rola robocza zakończy przetwarzanie wiadomości, chciałbym wywołać metodę w roli sieci, która następnie zasygnalizuje przeglądarce, że przetwarzanie zostało zakończone (przez SignalR). Proszę mi wybaczyć, jeśli nie jest to właściwe miejsce do zadawania pytań, ponieważ jest to raczej pytanie "najlepsza praktyka", a raczej prawdziwy problem. I do tej pory uważane 2 podejścia:Komunikacja między Azure między rolą pracownika a rolą sieciową

  1. Rola pracownika aktualizuje wiersz tabeli (w przechowywaniu stół) z przebiegu i zakończenia zadania. Brak sygnalizacji dla roli internetowej. Przeglądarka odczytuje ankietę bezpośrednio w pamięci tabeli (poprzez REST api) i dlatego wie, kiedy zadanie zostało zakończone. To działa dobrze (już to przetestowałem), chociaż nie podoba mi się podejście ciągłego odpytywania i chciałbym mieć rozwiązanie oparte na zdarzeniach. Ponadto, gdy klient otrzyma informację, że proces się zakończył, musi wykonać dodatkowe wywołanie metody internetowej api, aby nadać innym klientom (za pośrednictwem SignalR), że operacja została zakończona.

  2. Korzystanie Interrole communication wraz z SignalR (patrz przykładowy kod poniżej) działa również (już przetestowany również)

przykładowy kod:

var protocol = "http";  
var ipAddress = RoleEnvironment.Roles["XXX.YYY.Web"] 
     .Instances[0] 
     .InstanceEndpoints.ToArray() 
     .Where(ep => ep.Value.Protocol == protocol) 
     .First() 
     .Value.IPEndpoint.ToString(); 

var stringEndpoint = string.Format("{0}://{1}", protocol, ipAddress.ToString());     
Trace.WriteLine("Retrieved endpoint address: " + stringEndpoint, "Information");    
HubConnection connection = new HubConnection(stringEndpoint); 
IHubProxy proxy = connection.CreateHubProxy("MyWebHub"); 
connection.Start().Wait(); 

//later... 

proxy.Invoke("ProgressUpdated", clientId, progress); 

Moje pytanie brzmi: czy istnieją inne (lepsze) sposoby komunikowania się w kierunku Rola pracownika -> Rola sieci? Oznacza to, że uruchamia metodę w roli sieciowej, gdy rola robocza zakończy przetwarzanie? Metoda na roli internetowej będzie wtedy nadawać aktualizację wszystkim klientom za pośrednictwem SignalR. Przyjrzałem się także Event Hubs, ale według mnie konsumenci wydarzenia nadal działaliby w roli pracownika.

Odpowiedz

2

Ok po kilku dodatkowych prób i trochę badań mam wymyślić możliwego rozwiązania ... I był przy użyciu tego kodu

AzureServiceBus.QueueClient.OnMessage((message) => 
      { 
       try 
       { 
        // Process message from queue 
        Trace.WriteLine("Message received: " + ((BrokeredMessage)message).Label); 

        var breezeController = new BreezeController(); 
        breezeController.TestSignal(); 

        // Remove message from queue 
        message.Complete(); 
       } 
       catch (Exception) 
       { 
        // Indicates a problem, unlock message in queue 
        message.Abandon(); 
       } 
      }); 

wewnątrz onStart metody roli (nie rola pracownika) tak, żebym mógł odwołać się do mojej metody wewnątrz roli sieciowej (TestSignal() w tym przypadku), ale okazało się, że IHubContext był zawsze zerowy, gdy został wywołany z tej obsługi zdarzeń OnMessage, ponieważ należy (bardzo prawdopodobne) do innej AppDomain w ten sposób nawet statyczny Hub of signalR nie został udostępniony. Dlatego przeniosłem ten sam cały kod do pliku Global.asax.cs, aby udostępnić to samo AppDomain i teraz działa. Myślę, że pozostanę przy tym podejściu, ponieważ podoba mi się to znacznie bardziej niż ciągłe głosowanie.

+0

Podoba mi się ta implementacja! Nigdy wcześniej nie myślałem o tym wzorze i jest całkiem sprytne. Dobra robota! – Rogala

0

Myślę, że masz już wystarczającą wiedzę i doświadczenie wdrożeniowe, aby to osiągnąć. Używanie SignalR jest genialnym podejściem, nauczyłem się od ciebie.

Inne podejście mało bitowe, używam stałego odpytywania przy użyciu Azure Scheduler w celu wysłania wiadomości GET do WebRole.

IMO, jako rodzaj serwera webapi, odpytywanie jest najbardziej odpowiednim i niezawodnym podejściem do śledzenia tego, jaki serwer jest zaprojektowany.

+0

Dziękuję za opinie, nie jestem ekspertem, ale myślę, że Scheduler jest przeznaczony dla czegoś innego i ogólnie nie podoba mi się to podejście. Tak, prace ankietowe i mniej angażują rolę w sieci, ale nadal nie sądzę, że jest to najlepszy sposób na ... –

0

Trochę za późno na to pytanie :) ale zaimplementowaliśmy to określenie kolejki odpowiedzi i identyfikatorów sesji, do których rola sieci czeka po wysłaniu wiadomości do roli robota.Można dostosować go, aby uniknąć blokowania odpowiedzi natomiast rola internetowej czeka na odpowiedź roli pracownika (w naszym scenariuszu chcieliśmy specjalnie czekać)

WebRole

string sessionId = Guid.NewGuid().ToString(); 
[...] 
// put message in sync queue 
var message = new BrokeredMessage(request) 
{ 
    ReplyToSessionId = sessionId 
}; 
await ServiceBusConnector.Instance.SyncClient.SendAsync(message); 

// now listen to reply on session response queue (only accepts message on same session id) 
MessageSession session = await ServiceBusConnector.Instance.SyncResponseClient.AcceptMessageSessionAsync(sessionId); 

BrokeredMessage responseMessage = await session.ReceiveAsync(TimeSpan.FromMinutes(5)); 
await responseMessage.CompleteAsync(); 
await session.CloseAsync(); 

Response response = responseMessage.GetBody<Response>(); 
// process Worker Role's response 

Worker Role

// if a ReplyToSessionId has been specified, it means that the sender is 
    // actively waiting for a response 
    if (!String.IsNullOrEmpty(receivedMessage.ReplyToSessionId)) 
    { 
     // now respond on sync response queue 
     var responseMessage = new BrokeredMessage(response) 
     { 
      SessionId = receivedMessage.ReplyToSessionId 
     }; 

     // consider allowing client to specify a ReplyTo response queue (not needed for now) 
     await ServiceBusConnector.Instance.SyncResponseClient.SendAsync(responseMessage); 
    } 
0

także sprawdź tutaj Jessie's approach, aby bezpośrednio komunikować się z powrotem do aplikacji za pomocą HttpClient.

public class Functions 
{ 
    public static async Task ProcessQueueMessage([QueueTrigger("jobqueue")] Guid jobId, TextWriter log) 
    { 
     for (int i = 10; i <= 100; i+=10) 
     { 
      Thread.Sleep(400); 

      await CommunicateProgress(jobId, i); 
     } 
    } 

    private static async Task CommunicateProgress(Guid jobId, int percentage) 
    { 
     var httpClient = new HttpClient(); 

     var queryString = String.Format("?jobId={0}&progress={1}", jobId, percentage); 
     var request = ConfigurationManager.AppSettings["ProgressNotificationEndpoint"] + queryString; 

     await httpClient.GetAsync(request); 
    } 
} 
Powiązane problemy