protected virtual void Message( IEnumerable <IServerAddress> servers, ICacheRefresher refresher, MessageType messageType, IEnumerable <object> ids = null, Type idArrayType = null, string jsonPayload = null) { LogHelper.Debug <WebServiceServerMessenger>( "Performing distributed call for {0}/{1} on servers ({2}), ids: {3}, json: {4}", refresher.GetType, () => messageType, () => string.Join(";", servers.Select(x => x.ToString())), () => ids == null ? "" : string.Join(";", ids.Select(x => x.ToString())), () => jsonPayload ?? ""); try { // NOTE: we are messaging ALL servers including the local server // at the moment, the web service, // for bulk (batched) checks the origin and does NOT process the instructions again // for anything else, processes the instructions again (but we don't use this anymore, batched is the default) // TODO: see WebServerHelper, could remove local server from the list of servers // the default server messenger uses http requests using (var client = new ServerSyncWebServiceClient()) { var asyncResults = new List <IAsyncResult>(); LogStartDispatch(); // go through each configured node submitting a request asynchronously // NOTE: 'asynchronously' in this case does not mean that it will continue while we give the page back to the user! foreach (var n in servers) { // set the server address client.Url = n.ServerAddress; // add the returned WaitHandle to the list for later checking switch (messageType) { case MessageType.RefreshByJson: asyncResults.Add(client.BeginRefreshByJson(refresher.UniqueIdentifier, jsonPayload, Login, Password, null, null)); break; case MessageType.RefreshAll: asyncResults.Add(client.BeginRefreshAll(refresher.UniqueIdentifier, Login, Password, null, null)); break; case MessageType.RefreshById: if (idArrayType == null) { throw new InvalidOperationException("Cannot refresh by id if the idArrayType is null."); } if (idArrayType == typeof(int)) { // bulk of ints is supported var json = JsonConvert.SerializeObject(ids.Cast <int>().ToArray()); var result = client.BeginRefreshByIds(refresher.UniqueIdentifier, json, Login, Password, null, null); asyncResults.Add(result); } else // must be guids { // bulk of guids is not supported, iterate asyncResults.AddRange(ids.Select(i => client.BeginRefreshByGuid(refresher.UniqueIdentifier, (Guid)i, Login, Password, null, null))); } break; case MessageType.RemoveById: if (idArrayType == null) { throw new InvalidOperationException("Cannot remove by id if the idArrayType is null."); } // must be ints asyncResults.AddRange(ids.Select(i => client.BeginRemoveById(refresher.UniqueIdentifier, (int)i, Login, Password, null, null))); break; } } // wait for all requests to complete var waitHandles = asyncResults.Select(x => x.AsyncWaitHandle); WaitHandle.WaitAll(waitHandles.ToArray()); // handle results var errorCount = 0; foreach (var asyncResult in asyncResults) { try { switch (messageType) { case MessageType.RefreshByJson: client.EndRefreshByJson(asyncResult); break; case MessageType.RefreshAll: client.EndRefreshAll(asyncResult); break; case MessageType.RefreshById: if (idArrayType == typeof(int)) { client.EndRefreshById(asyncResult); } else { client.EndRefreshByGuid(asyncResult); } break; case MessageType.RemoveById: client.EndRemoveById(asyncResult); break; } } catch (WebException ex) { LogDispatchNodeError(ex); errorCount++; } catch (Exception ex) { LogDispatchNodeError(ex); errorCount++; } } LogDispatchBatchResult(errorCount); } } catch (Exception ee) { LogDispatchBatchError(ee); } }
protected virtual void PerformDistributedCall( IEnumerable <IServerAddress> servers, ICacheRefresher refresher, MessageType dispatchType, IEnumerable <object> ids = null, Type idArrayType = null, string jsonPayload = null) { //We are using distributed calls, so lets make them... try { //TODO: We should try to figure out the current server's address and if it matches any of the ones // in the ServerAddress list, then just refresh directly on this server and exclude that server address // from the list, this will save an internal request. using (var cacheRefresher = new ServerSyncWebServiceClient()) { var asyncResultsList = new List <IAsyncResult>(); LogStartDispatch(); // Go through each configured node submitting a request asynchronously //NOTE: 'asynchronously' in this case does not mean that it will continue while we give the page back to the user! foreach (var n in servers) { //set the server address cacheRefresher.Url = n.ServerAddress; // Add the returned WaitHandle to the list for later checking switch (dispatchType) { case MessageType.RefreshByJson: asyncResultsList.Add( cacheRefresher.BeginRefreshByJson( refresher.UniqueIdentifier, jsonPayload, Login, Password, null, null)); break; case MessageType.RefreshAll: asyncResultsList.Add( cacheRefresher.BeginRefreshAll( refresher.UniqueIdentifier, Login, Password, null, null)); break; case MessageType.RefreshById: if (idArrayType == null) { throw new InvalidOperationException("Cannot refresh by id if the idArrayType is null"); } if (idArrayType == typeof(int)) { var serializer = new JavaScriptSerializer(); var jsonIds = serializer.Serialize(ids.Cast <int>().ToArray()); //we support bulk loading of Integers var result = cacheRefresher.BeginRefreshByIds(refresher.UniqueIdentifier, jsonIds, Login, Password, null, null); asyncResultsList.Add(result); } else { //we don't currently support bulk loading of GUIDs (not even sure if we have any Guid ICacheRefreshers) //so we'll just iterate asyncResultsList.AddRange( ids.Select(i => cacheRefresher.BeginRefreshByGuid( refresher.UniqueIdentifier, (Guid)i, Login, Password, null, null))); } break; case MessageType.RemoveById: //we don't currently support bulk removing so we'll iterate asyncResultsList.AddRange( ids.Select(i => cacheRefresher.BeginRemoveById( refresher.UniqueIdentifier, (int)i, Login, Password, null, null))); break; } } List <WaitHandle> waitHandlesList; var asyncResults = GetAsyncResults(asyncResultsList, out waitHandlesList); var errorCount = 0; // Once for each WaitHandle that we have, wait for a response and log it // We're previously submitted all these requests effectively in parallel and will now retrieve responses on a FIFO basis foreach (var t in asyncResults) { var handleIndex = WaitHandle.WaitAny(waitHandlesList.ToArray(), TimeSpan.FromSeconds(15)); try { // Find out if the call succeeded switch (dispatchType) { case MessageType.RefreshByJson: cacheRefresher.EndRefreshByJson(t); break; case MessageType.RefreshAll: cacheRefresher.EndRefreshAll(t); break; case MessageType.RefreshById: if (idArrayType == null) { throw new InvalidOperationException("Cannot refresh by id if the idArrayType is null"); } if (idArrayType == typeof(int)) { cacheRefresher.EndRefreshById(t); } else { cacheRefresher.EndRefreshByGuid(t); } break; case MessageType.RemoveById: cacheRefresher.EndRemoveById(t); break; } } catch (WebException ex) { LogDispatchNodeError(ex); errorCount++; } catch (Exception ex) { LogDispatchNodeError(ex); errorCount++; } } LogDispatchBatchResult(errorCount); } } catch (Exception ee) { LogDispatchBatchError(ee); } }