2012-04-16 18 views
12

ci troviamo di fronte con il compito di convertire un servizio REST basato sul codice personalizzato per Web API. Il servizio ha una notevole quantità di richieste e opera su dati che potrebbero richiedere del tempo per essere caricati, ma una volta caricato può essere memorizzato nella cache e utilizzato per soddisfare tutte le richieste in arrivo. La versione precedente del servizio avrebbe un thread responsabile del caricamento dei dati e del caricamento nella cache. Per impedire a IIS di esaurire i thread di lavoro, i client riceverebbero una risposta "torna indietro" finché la cache non fosse pronta.Web e la scalabilità

La mia comprensione dell'API Web è che ha un comportamento asincrono incorporato operando sulle attività e, di conseguenza, il numero di richieste non sarà direttamente correlato al numero di thread fisici trattenuti.

Nella nuova implementazione del servizio Ho intenzione di lasciare che le richieste di aspettare fino a quando la cache è pronto e poi fare una risposta valida. Ho fatto uno schizzo molto approssimativa del codice per illustrare:

public class ContactsController : ApiController 
{ 
    private readonly IContactRepository _contactRepository; 

    public ContactsController(IContactRepository contactRepository) 
    { 
     if (contactRepository == null) 
      throw new ArgumentNullException("contactRepository"); 
     _contactRepository = contactRepository; 
    } 

    public IEnumerable<Contact> Get() 
    { 
     return _contactRepository.Get(); 
    } 
} 

public class ContactRepository : IContactRepository 
{ 
    private readonly Lazy<IEnumerable<Contact>> _contactsLazy; 

    public ContactRepository() 
    { 
     _contactsLazy = new Lazy<IEnumerable<Contact>>(LoadFromDatabase, 
      LazyThreadSafetyMode.ExecutionAndPublication); 
    } 

    public IEnumerable<Contact> Get() 
    { 
     return _contactsLazy.Value; 
    } 

    private IEnumerable<Contact> LoadFromDatabase() 
    { 
     // This method could be take a long time to execute. 
     throw new NotImplementedException(); 
    } 
} 

prega di non mettere troppo valore nella progettazione del codice - è costruito solo per illustrare il problema e non è come abbiamo fatto in la soluzione reale. IContactRepository è registrato nel contenitore IoC come un singleton e viene iniettato nel controller. Lazy con LazyThreadSafetyMode.ExecutionAndPublication garantisce che solo il primo thread/richiesta stia eseguendo il codice di inizializzazione, i seguenti requisiti sono bloccati fino al completamento dell'inizializzazione.

L'API Web sarebbe in grado di gestire 1000 richieste in attesa del completamento dell'inizializzazione mentre altre richieste che non lo colpiscono sono in servizio e senza che IIS stia esaurendo i thread di lavoro?

risposta

10

Tornando Task<T> dall'azione permetterà il codice da eseguire sui precedenti filo (ThreadPool) e rilasciare il filo IIS. Quindi, in questo caso, vorrei cambiare

public IEnumerable<Contact> Get() 

a

public Task<IEnumerable<Contact>> Get() 

Ricordarsi di restituire un iniziato compito altrimenti il ​​filo sarà solo sedersi e non fare nulla.

pigro implementazione, mentre può essere utile, ha ottenuto poco a che fare con il comportamento delle API Web. Quindi non ho intenzione di commentare su questo. Con o senza pigro, il tipo di reso basato sull'attività è la strada da percorrere per operazioni a lungo termine.

Ho due post di blog su questo che sono probabilmente utili a voi: here e here.

Problemi correlati