2012-05-23 13 views
5

Ho una situazione abbastanza strana.Strano comportamento con le classi uri e WebClient sul pacchetto SSIS

ho questo molto semplice pacchetto:

enter image description here

  • Task "ottenere l'elenco" recupera una tabella di dati da un assieme con un colonna e un elenco di URL per essere eseguito in una variabile oggetto .
  • Il "foreach" loop loop attraverso la variabile oggetto e carica l'URL in una stringa URL variabile
  • Il "run", chiama l'URL con questo codice (del 2005 in modo da Im bloccato con VB):

    Dim myURI As New Uri("http://" + Dts.Variables("URL").Value.ToString()) 
    Dim myWebClient As New System.Net.WebClient 
    myWebClient.OpenReadAsync(myURI) 
    

l'URL di essere chiamato è interno e solo legge i parametri ed esegue una serie di operazione che richiederà un certo tempo, è per questo che ho usato "OpenReadAsync"

Il mio problema è: se ho 4 URL da eseguire, il pacchetto ne esegue solo 2. Il ciclo si interrompe 4 volte, lo script è chiamato 4 volte (posso vedere se lo faccio il debug), la linea myWebClient.OpenReadAsync(myURI) viene eseguita 4 volte con 4 valori diversi, ma vengono effettuate solo 2 chiamate all'URL.

Se eseguo nuovamente il pacchetto, vengono richiamati gli altri 2 URL, che dimostrano che non c'è niente di sbagliato nell'URL e Se richiamo i 4 url ​​manualmente sul browser (su 4 schede per esempio) uno subito dopo, tutti producono il risultato atteso, il che dimostra che non c'è niente di sbagliato nel codice che analizza l'URL.

Quindi mi rimane il codice VB, è la prima volta che utilizzo uri e WebClient, quindi mi chiedo se sto facendo qualcosa di sbagliato. Ho anche provato ad aggiungere 5 secondi di sonno tra le chiamate, ma senza fortuna.

Qualsiasi aiuto sarebbe apprezzato. Grazie

+0

Che cosa succede se si passa sopra a utilizzando il metodo sincrono OpenRead? – billinkc

+0

Ciao billinkc! Ottengo un timeout dopo la seconda esecuzione. È strano perché i 4 url ​​che ho dovrebbero essere eseguiti in pochi secondi, infatti posso vedere (ho un log) che il secondo ha funzionato 5 secondi dopo il primo. E se eseguo il pacchetto la seconda volta, i 2 url rimanenti vengono eseguiti correttamente, quindi definitivamente è qualcosa con il fatto di chiamare il codice più di 2 volte – Diego

+0

Ogni volta che mi imbatto in problemi di codice "strani" in SSIS, faccio il dump del codice accedere a un'app console .NET e vedere se riesco a riprodurre il comportamento lì. Immagino che tu l'abbia già provato, ma nel caso non lo avessi fatto, quello potrebbe essere un posto in cui girare visto visto che non c'è stato molto amore per la tua generosità. Inoltre, come è il tuo codice completo? Qualche possibilità che vengano chiamati tutti e 4 gli URL, ma dal momento che sono chiamate asincrone, non osservi gli effetti solo più tardi? Cosa succede se metti un thread.sleep più lungo, qualcosa per abbinare la durata del processo previsto? Sconfigge lo scopo di asincrono, lo so ma può far luce un po 'di luce – billinkc

risposta

4

Tutti i browser si limitano a 2 richieste per host, per evitare di sovraccaricare l'host. .NET segue questa regola e consente solo 2 connessioni simultanee a un host. È possibile modificare questo limite modificando il file di configurazione dell'applicazione o il codice.

Il ritardo aggiunto allo script non ha funzionato perché non è stato chiamato Dispose nell'istanza WebClient. La classe WebClient mantiene aperta la propria connessione fino a quando non la si disfa per leggere il flusso di risposta.Altrimenti non sarà più possibile connettersi allo stesso host finché il garbage collector non raccoglierà il client.

Inoltre, OpenReadAsync apre lo stream al client e assicura che rimanga aperto a meno che non lo si chiuda o venga raccolto. È necessario utilizzare uno dei DownloadXXXAsync per evitare l'apertura dello stream senza un motivo.

Una soluzione migliore sarebbe chiamare DownloadStringAsync e disporre del client nell'evento DownloadStringAsyncCompleted.

UPDATE:

ServicePointManager.DefaultConnectionLimit è memorizzato in un campo statico che significa che la sua portata è l'intero AppDomain. SSIS utilizza un singolo AppDomain per ogni esecuzione del pacchetto in modo che il valore influenzi l'intero pacchetto.

Se si desidera modificare il limite di connessione per un solo host utilizzando FindServicePoint, è possibile creare un ServicePoint per l'indirizzo host e impostare il limite solo per questo indirizzo:

var myTarget= ServicePointManager.FindServicePoint(new Uri("http://www.google.com")); 
myTarget.ConnectionLimit = 10; 
+0

Ho aggiunto all'interno di ma ho ancora lo stesso comportamento – Diego

+0

Ignora il mio ultimo commento. Ho aggiunto il codice dal tuo secondo link alla mia attività di script con un limite di 5 e ha funzionato perfettamente. Quello che non capisco è: non ho fatto alcun riferimento al mio oggetto WebClient. Come ha "letto" questa impostazione? È un ambiente globale? Grazie mille – Diego

+0

Il valore è memorizzato in un campo statico che significa che è globale per l'AppDomain. SSIS utilizza un singolo appdomain per ogni esecuzione del pacchetto, quindi non vi è alcun rischio che la modifica incida su altre esecuzioni. Aggiornato la risposta con il codice per modificare il limite per un solo indirizzo solo –

1
  1. Cercare di estendere il timeout per ogni attività e attività secondaria.

  2. Non mi è stato chiesto, ma avrei codificato un task come questo invece di usare SSIS. SSIS è perfetto per ETL ma non molto altro!