.NET 3.5, VS2008, servizio WCF utilizzando BasicHttpBindingWCF, BasicHttpBinding: Stop nuove connessioni, ma consente connessioni esistenti di continuare
Ho un servizio WCF ospitato in un servizio di Windows. Quando il servizio di Windows si arresta, a causa di aggiornamenti, manutenzione programmata, ecc, ho bisogno di chiudere con grazia il mio servizio WCF. Il servizio WCF ha metodi che possono richiedere diversi secondi per essere completato e il volume tipico è di 2-5 chiamate al secondo al metodo. Devo arrestare il servizio WCF in modo da consentire il completamento di qualsiasi metodo di chiamata precedente, mentre si rifiuta ogni nuova chiamata. In questo modo, posso raggiungere uno stato silenzioso in ~ 5-10 secondi e quindi completare il ciclo di spegnimento del mio servizio Windows.
La chiamata al numero ServiceHost.Close sembra l'approccio corretto, ma chiude immediatamente le connessioni client, senza attendere il completamento dei metodi in corso. Il mio servizio WCF completa il suo metodo, ma non c'è nessuno a cui inviare la risposta, perché il client è già stato disconnesso. Questa è la soluzione suggerita da this question.
Ecco la sequenza di eventi:
- client chiama il metodo sul servizio, utilizzando il VS generato classe proxy
- Servizio inizia l'esecuzione del metodo del servizio
- Service riceve una richiesta di arresto
- Servizio chiama ServiceHost.Close (o BeginClose)
- Il client viene disconnesso e riceve un System.ServiceModel.CommunicationException
- Il servizio completa il metodo di servizio.
- Eventualmente il servizio rileva che non ha più lavoro da fare (tramite la logica dell'applicazione) e termina.
Quello che mi serve è che le connessioni client siano mantenute aperte in modo che i client sappiano che i loro metodi di servizio sono stati completati con successo. In questo momento ottengono solo una connessione chiusa e non sanno se il metodo di servizio è stato completato con successo o meno. Prima di usare WCF, stavo usando i socket ed ero in grado di farlo controllando direttamente il socket. (ovvero interrompere il ciclo Accept mentre si sta ancora ricevendo e invia)
È importante che la porta HTTP dell'host sia chiusa in modo che il firewall upstream possa indirizzare il traffico verso un altro sistema host, ma le connessioni esistenti rimangono aperte per consentire l'esistente chiamate di metodo per completare.
C'è un modo per realizzare questo in WCF?
Le cose che ho provato:
- ServiceHost.Close() - chiude i clienti subito
- ServiceHost.ChannelDispatchers - Call Listener.Close() su ogni - non sembra di fare nulla
- ServiceHost.ChannelDispatchers - chiamare CloseInput() su ogni - chiude i clienti subito
- Override ServiceHost.OnClosing() - mi permette di ritardare l'chiudere fino a quando decido che è ok per chiudere, ma le nuove connessioni sono consentite durante questo tempo
- Rimuovere l'endpoint utilizzando technique described here. Questo cancella tutto.
- Esecuzione di uno sniffer di rete per osservare ServiceHost.Close().L'host chiude la connessione, nessuna risposta viene inviata.
Grazie
Modifica: Purtroppo non posso implementare una risposta di consulenza a livello di applicazione che il sistema si sta spegnendo, perché i clienti del settore sono già schierate. (Controllo solo il servizio, non i client)
Modifica: Ho utilizzato il Reflector di Redgate per esaminare l'implementazione Microsoft di ServiceHost.Close. Sfortunatamente, chiama alcune classi di helper internal
a cui il mio codice non può accedere.
Modifica: Non ho trovato la soluzione completa che stavo cercando, ma il suggerimento di Benjamin di utilizzare IMessageDispatchInspector per rifiutare le richieste prima di accedere al metodo di servizio è stato il più vicino.
La tua idea di ridefinire gli indirizzi degli endpoint è interessante, ma sembra che ci sia solo un ServiceHost .AddServiceEndpoint. La struttura ChannelDispatcher.Endpoints è di tipo get-only. Sai come avresti cambiato gli endpoint del servizio dopo che ServiceHost.Open() è stato chiamato? –
Ciao. Scusate le cose sopra erano solo suggerimenti "pensando ad alta voce". Sto provando a creare una configurazione di prova ora e ho limitato (in altre parole: non sono sicuro se puoi usarlo così com'è) successo con un comportamento ora. Aggiornerà il mio post in un secondo. –
Buona idea, ho già avuto un comportamento IDispatchMessageInspector per registrare il traffico, quindi ho aggiunto un controllo per vedere se l'host si sta spegnendo, e in tal caso, chiama Message.Close(). Ciò provoca una FaultException sul client, ma almeno il client riceve le risposte per le chiamate di servizio ricevute prima dell'arresto. La porta in entrata è ancora aperta, sfortunatamente, ma potrebbe non esserci alcun problema. –