2012-03-12 17 views
12

Ho un sito Web asp.net-mvc e le persone gestiscono un elenco di progetti. Sulla base di alcuni algoritmi, posso dire se un progetto non è aggiornato. Quando un utente effettua l'accesso, voglio che mostri il numero di progetti obsoleti (simile a quando vedo un numero di aggiornamenti nella Posta in arrivo).Qual è il modo consigliato per creare funzionalità simili alla "Posta in arrivo" di Stackoverflow?

L'algoritmo per calcolare i progetti stantii è un po 'lento, quindi se ogni volta che un utente si connette, devo:

  1. Eseguire una query per tutti i progetti in cui sono il proprietario
  2. Eseguire l'IsStale () algoritmo
  3. visualizzare il conteggio in cui IsStale = true

la mia ipotesi è che sarà molto lentamente. Inoltre, su tutto il progetto scrivere, dovrei ricalcolare quanto sopra per vedere se è cambiato.

Un'altra idea che avevo era di creare una tabella ed eseguire un lavoro ogni minuto per calcolare i progetti obsoleti e memorizzare l'ultimo conteggio in questa tabella delle metriche. Quindi basta interrogare che quando gli utenti effettuano l'accesso. Il problema è che devo ancora mantenere la tabella in sincronia e se viene eseguita una nuova ricalca una volta al minuto, se la gente aggiorna i progetti, non cambierà il valore fino a dopo un minuto.

Qualche idea per un modo veloce e scalabile per supportare questo concetto di posta in arrivo per avvisare gli utenti del numero di articoli da esaminare ??

risposta

10

Il primo passo è sempre un'adeguata analisi dei requisiti. Supponiamo che io sia un Project Manager. Accedo al sistema e visualizza il mio unico progetto come in tempo. Uno sviluppatore arriva nel mio ufficio e mi dice che c'è un ritardo nella sua attività. Seleziono l'attività dello sviluppatore e cambio la sua durata. Il sistema visualizza ancora il mio progetto come in tempo, quindi sono felice di lasciare il lavoro.

Come pensi che mi sentirei se ricevessi una telefonata alle 3:00 dal cliente chiedendomi una spiegazione del motivo per cui il progetto non è più in tempo? Ovviamente, abbastanza sorpreso, perché il sistema non mi ha avvisato in alcun modo. Perché è successo? Perché ho dovuto aspettare 30 secondi (perché non solo 1 secondo?) Per la prossima esecuzione di un lavoro programmato per aggiornare lo stato del progetto.

Questo non può essere una soluzione. Un avviso deve essere inviato immediatamente all'utente, anche se occorrono 30 secondi per eseguire il processo IsStale(). Mostra all'utente un'immagine loading... o qualsiasi altra cosa, ma assicurati che l'utente abbia dati precisi.

Ora, per quanto riguarda l'implementazione, non è possibile eseguire nulla per evitare il problema precedente: sarà necessario eseguire tale processo quando qualcosa che influisce su alcune date di scadenza cambia. Tuttavia, ciò che puoi fare non è eseguire inutilmente quel processo. Ad esempio, hai accennato al fatto che potresti eseguirlo ogni volta che l'utente effettua l'accesso. Cosa succede se 2 o più utenti accedono e visualizzano lo stesso progetto e non cambiano nulla? Non sarebbe necessario eseguire il processo due volte.

Inoltre, se si assicura che il processo venga eseguito quando l'utente aggiorna il progetto, non sarà necessario eseguire il processo in qualsiasi momento.In conclusione, questo schema presenta i seguenti vantaggi e svantaggi rispetto alla soluzione "polling":

Vantaggi

  • Nessun processo pianificato
  • Non viene eseguito il processo non necessari (questo è discutibile, perché si potrebbe impostare una bandiera dirty sul progetto e solo eseguirlo se è true)
  • Nessun query non necessarie del valore dirty
  • L'utente sarà sempre informato dello stato attuale e reale del progetto (che è di gran lunga, la voce più importante per affrontare in qualsiasi soluzione fornita)

Svantaggi

  • Se un l'utente aggiorna un progetto e lo ripristina in pochi secondi, il processo verrebbe eseguito due volte (nello schema di polling il processo potrebbe non essere eseguito nemmeno una volta in quel periodo, a seconda della frequenza programmata)
  • l'utente che aggiorna il progetto dovrà attendere il completamento del processo

Passando al modo in cui si implementa il sistema di notifica in modo simile a StackOverflow, è una domanda abbastanza diversa. Immagino tu abbia una relazione molti-a-molti con utenti e progetti. La soluzione più semplice sarebbe l'aggiunta di un singolo attributo al rapporto tra tali entità (tabella centrale ):

cardinalità: Un utente ha molti progetti. Un progetto ha molti utenti

In questo modo quando si esegue il processo è necessario aggiornare Has_pending_notifications di ciascun utente con il nuovo risultato. Ad esempio, se un utente aggiorna un progetto e non è più in tempo, è necessario impostare su Has_pending_notifications il campo tutti gli utenti in modo che siano a conoscenza della situazione. Allo stesso modo, impostalo su false quando il progetto è in tempo (ho capito che vuoi solo assicurarti che le notifiche vengano visualizzate quando il progetto non è più in tempo).

Prendendo l'esempio di StackOverflow, quando un utente legge una notifica è necessario impostare il flag su false. Assicurati di non utilizzare i timestamp per indovinare se un utente ha letto una notifica: l'accesso non significa leggere le notifiche.

Infine, se la notifica in sé è abbastanza complessa, è possibile allontanarlo dal rapporto tra utenti e progetti e andare per qualcosa di simile a questo:

cardinalità: un utente ha molti progetti . Un progetto ha molti utenti. Un utente ha molte notifiche. Una notifica ha un utente. Un progetto ha molte notifiche.Una notifica ha un progetto.

spero qualcosa che ho detto ha un senso, o ti danno qualche altra idea migliore :)

3

Rendere un campo "obsoleto". Eseguire un'istruzione SQL che aggiorna stale = 1 con tutti i record in cui stale = 0 AND (che l'algoritmo restituisce true). Quindi eseguire un'istruzione SQL che seleziona tutti i record dove stantio = 1.

La ragione per questo lavoro veloce è perché parser SQL, come PHP, non dovrebbero fare la seconda metà del AND dichiarazione Se la prima metà rendimenti veri, che lo rende una corsa molto veloce attraverso l'intera lista, controllando tutti i record, cercando di renderli stantii se non già stantio. Se è già scaduto, l'algoritmo non verrà eseguito, risparmiando tempo. Se non lo è, verrà eseguito l'algoritmo per vedere se è diventato obsoleto, quindi sarà impostato su 1.

La seconda query restituisce quindi tutti i record non aggiornati dove stantio = 1.

0

Si può fare questo:

Nel database cambiare il timestamp ogni volta che un progetto è accessibile dall'utente. Quando l'utente esegue il login, estrae tutti i loro progetti. Controlla il timestamp e confrontalo con la data odierna, se è precedente a n giorni, aggiungilo all'elenco stantio. Non credo che confrontare le date porterà a una logica lenta.

+0

suo metodo IsStale(), che è lento – leora

+1

Tempo confronto timbro non dovrebbe essere lento, ma la vostra altra opzione è quella di aggiungere questa logica sul lato database. Se è possibile, creare una stored procedure che esegue il confronto e restituisce il risultato come una colonna aggiuntiva. – evasilchenko

+0

IsStale() NON sta semplicemente confrontando la data/ora.è un algoritmo più complicato per vedere se i dati non sono aggiornati in base a un numero di fattori – leora

6

Si può fare come segue:

  1. Per ogni record utente aggiunge un campo datetime DIRE l'ultima volta che il calcolo è stato fatto lento. Chiamalo LastDate.
  2. Ad ogni progetto aggiungere un valore booleano per indicare se deve essere elencato.Chiamatela: Selezionato
  3. Quando si esegue la procedura di Slow set si aggiornano i selezionati Campi
  4. Ora, quando l'utente se ultimoData è abbastanza vicino per ora si utilizzano i risultati dell'ultimo calcolo lento e prendi tutto il progetto con Selezionato true. Altrimenti risuona il calcolo lento. La procedura di cui sopra è ottimale, perché calcola la procedura lenta SOLO SE EFFETTIVAMENTE NECESSARIA, mentre eseguendo una procedura a intervalli di tempo fissi ... ha il rischio di perdere tempo perché forse l'utente utilizzerà il risultato di un calcolo .
0

penso che le domande fondamentali devono essere risolti prima di pensare a basi di dati e codice. Il principale di questi è: "Perché IsStale() è lento?"

Da commenti altrove è chiaro che il concetto che questo è lento non è negoziabile. Questo calcolo è fuori dalle tue mani? I risultati sono resistenti al caching? Quale livello di cambiamento innesca il ricalcolo.

aver scritto sistemi di pianificazione, in passato, ci sono due tipi di cambiamenti: quelli che possono accadere entro il lasco e quelli che causano cascata cambiamenti di programma. Allo stesso modo, ci sono due tipi di ricostruzione: totale e locale. Le ricostruzioni totali sono ovvie; le ricostruzioni locali cercano di minimizzare il "danno" ad altre risorse pianificate.

Ecco il nocciolo della questione: se si dispone di una ricostruzione totale su ogni aggiornamento, è possibile osservare ritardi di 30 minuti dal momento della modifica al momento in cui la pianificazione è stabile. (Sto basandomi sulla mia esperienza con il tempo di ricostruzione di un sistema ERP con un carico di lavoro molto complesso).

Se la realtà del sistema è che tali compiti richiedere 30 minuti, con un obiettivo di progettazione di gratificazione immediata per gli utenti è contrario alla verità terra della questione. Tuttavia, è possibile che rilevi l'incoerenza della pianificazione molto più veloce della ricostruzione. In questo caso potresti mostrare all'utente "il programma è stato sovraccaricato, ricalcolare i nuovi tempi finali" o qualcosa di simile ... ma sospetto che se si inseriscono molte modifiche di programma da parte di diversi utenti contemporaneamente il sistema si degraderebbe in una visualizzazione continua di tale avviso. Tuttavia, si ottiene almeno il vantaggio che si potrebbero verificare modifiche in batch in un periodo di tempo per la successiva ricostruzione.

E 'per questo motivo che la maggior parte dei problemi di programmazione che ho visto in realtà non fanno in tempo reale ri-calcoli. Nel contesto della situazione ERP c'è un master di pianificazione che è responsabile per la pianificazione della fabbrica e qualsiasi cambiamento viene incanalato attraverso di essi. Il programma "master" è stato rigenerato prima di ogni turno (i turni erano 12 ore, quindi due volte al giorno) e durante il turno i ritardi venivano elaborati tramite modifiche "locali" che non mischiavano il programma principale fino al successivo blocco di 12 ore.

In un (progettazione software) situazione molto più semplice il programma è stato aggiornato una volta al giorno in seguito ai progressi della giornata di segnalazione. Le cattive notizie sono state consegnate durante la mischia del mattino successivo, insieme al programma aggiornato.

Per farla breve, sto pensando che forse questo è un momento "unask the question", in cui l'assunto deve essere sfidato. Se il re-computazione è abbastanza grande da rendere gli aggiornamenti continui poco pratici, allora è necessario allineare le aspettative con la realtà. O l'algoritmo ha bisogno di lavoro (ottimizzazione per le modifiche locali), la farm hardware ha bisogno di espansione o il tempo delle aspettative di "verità" deve essere ricalibrato.

Una risposta più raffinata sarebbe francamente richiederebbe ulteriori dettagli di "dare per scontato un processo costoso", perché i punti corretti di attacco a quel processo sono impossibili da conoscere.