Mi chiamo Utkarsh Jadhav e sono uno studente del master in Informatica alla Northeastern University, qui a Boston. Ho trascorso le ultime tredici settimane in edX lavorando con il team della piattaforma. Il team della piattaforma è responsabile della creazione dell'infrastruttura per i prodotti Open edX, lavorando in particolare per velocizzare l'esecuzione del codice. In questo post, vorrei evidenziare uno dei miei progetti più importanti, Call Stack Manager. È uno strumento che tiene traccia di stack di chiamate univoci di funzioni, metodi e classi Django Model.
Modulo per studenti del materiale didattico (CSM) eCronologia del modulo per studenti Courseware (CSMH) in edx-platform code sono responsabili del mantenimento dello stato utente degli studenti che tentano problemi e dei rispettivi voti. Il sito web edx.org ha recentemente raggiunto 5 milioni di studenti; le dimensioni crescenti di CSM e CSMH stanno causando serie preoccupazioni per quanto riguarda lo spazio e le interruzioni del database. La suddivisione delle aree di codice monolitiche come LMS e CMS nella piattaforma edx è un'esigenza vitale poiché la base di codice e il volume del database aumentano.
client stato utente edX (eUSC)
In origine, la struttura del client dello stato utente era la seguente:

Struttura precedente di User State Client che mostra la comunicazione tra la piattaforma edx e il database MySQL tramite CSM/CSMH
L'intera struttura era sotto piattaforma edx/edx. Il client dello stato utente stava comunicando direttamente con le tabelle MySQL denominate courseware_studentmodule e courseware_studentmodulehistorytramite DjangoORM.
Quando ho iniziato il mio tirocinio, il team conosceva già gli aspetti negativi di questa architettura. Per risolvere questo problema, ho aiutato a implementare l'architettura proposta che è mostrata nella figura seguente:

Struttura proposta di User State Client che mostra un livello edx-user-state-client tra la piattaforma e il back-end del database
In questa nuova architettura, edx-utente-stato-client funge da strato tra la piattaforma edx e i backend del database. Ci sono molti vantaggi nell'usare una tale struttura:
- eUSC agirà come un'unica interfaccia a un livello astratto attraverso la quale verranno effettuate tutte le chiamate al database. Tale modello alla fine aiuterà in una comunicazione efficace con il database.
- eUSC consentirà anche un facile passaggio tra diversi backend. Questa API consentirà una scelta per i back-end, anche per le attività distribuite.
Come primo passo verso la creazione di questa struttura, ho creato un repository denominato edx/edx-utente-stato-client. Questo repository contiene l'interfaccia XBlockUserStateClient, che si occupa di tutte le chiamate effettuate dalle classi modello Django con il database.
Chiama il gestore dello stack
Migliori XBlockUserStateClient è responsabile di effettuare tutte le chiamate al database. Tuttavia, considerando l'immensa dimensione della base di codice edX, l'uso di estensioni di terze parti (es. XBlocks) e molte chiamate effettuate al database in vari punti, vale davvero la pena di intercettare le chiamate al database che non vengono effettuate tramite l'interfaccia XBlockUserStateClient.
Per rispondere a questa esigenza, ho sviluppato una libreria chiamata Chiama il gestore dello stack. Questa è una libreria che ci permette di tenere traccia delle chiamate che non vengono effettuate tramite interfaccia e che stanno comunicando direttamente con il database. Call Stack Manager registra tali chiamate nel registro LMS.
La libreria implementa due decoratori principali:
- @trackit – che traccia l'entità decorata
- @Non tracciare – che interrompe il tracciamento delle entità decorate da @trackit.
La necessità principale di sviluppare questa libreria era tenere traccia delle chiamate delle classi Model in CSM e CSMH, principalmente Modulo Studente e StudentModuleHistory. La comunicazione con i database in Django viene eseguita da classi definite dall'utente che sottoclasse il Classe "Modello" di Django. Le classi modello usano il API QuerySet per creare, recuperare e aggiornare database. Le chiamate effettuate dall'API QuerySet possono essere sovrascritte utilizzando un gestore personalizzato denominato CallStack Manager – definito nella libreria Call Stack Manager. In questo modo è stato gestito il caso particolare del tracciamento delle classi Django Model che accedono direttamente al database.
Durante l'esecuzione di Call Stack Manager nella sua versione iniziale, ho riscontrato i seguenti problemi:
- I registri delle chiamate sono stati creati ripetutamente, ingombrando il registro LMS.
- Molte chiamate di cui già sapevamo sono state registrate inutilmente.
- I registri delle chiamate contenevano frame non necessari, rendendolo lungo e difficile da leggere.
Per affrontare questi problemi, ho introdotto un nuovo decoratore, chiamato @Non tracciare, che interrompe il rilevamento per l'ambito della funzione decorata con questo decoratore. In generale, le chiamate a un metodo monitorato possono essere suddivise in due categorie: quelle effettuate dalla nuova implementazione dell'interfaccia e quelle che non lo sono. Le chiamate che già conosciamo e ci aspettiamo, ovvero quelle dalla nuova implementazione, possono essere ignorate, poiché siamo interessati solo a catturare le chiamate di cui non siamo a conoscenza. Quindi, usiamo questo @Non tracciare decorator per nascondere le chiamate tracciate effettuate da tale implementazione. A questo punto, le uniche chiamate monitorate saranno quelle effettuate dall'esterno della nuova implementazione.
In questo modo, le chiamate attese e note effettuate al database (ad es. tramite interfaccia XBlockUserStateClient) non sono stati registrati, fornendoci un quadro chiaro di ciò che stavano facendo le chiamate sconosciute. Inoltre, i frame duplicati nello stack di chiamate sono stati filtrati utilizzando i filtri delle espressioni regolari. In questo modo il numero delle chiamate registrate risultava inferiore, più preciso e più leggibile.
Un esempio di uno stack di chiamate menzionato sopra è il seguente:
Registrazione del nuovo stack di chiamate numero 4 per:
File “/edx/app/edxapp/edx-platform/lms/djangoapps/instructor/views/api.py”, riga 240, in wrapping
return funzione(*args, **kwargs)
File “/edx/app/edxapp/edx-platform/lms/djangoapps/instructor/views/api.py”, riga 176, in wrapping
return funzione(*args, **kwargs)
File “/edx/app/edxapp/edx-platform/lms/djangoapps/instructor/views/api.py”, riga 127, in wrapping
return func(richiesta, *args, **kwargs)
File "/edx/app/edxapp/edx-platform/lms/djangoapps/instructor/views/api.py", riga 1896, in rescore_problem
istruttore_task.api.submit_rescore_problem_for_student(richiesta, module_state_key, studente)
File “/edx/app/edxapp/edx-platform/lms/djangoapps/instructor_task/api.py”, riga 110, in submit_rescore_problem_for_student
return submit_task(richiesta, tipo_attività, classe_attività, chiave_utilizzo.chiave_corso, input_attività, chiave_attività)
File "/edx/app/edxapp/edx-platform/lms/djangoapps/instructor_task/api_helper.py", riga 346, in submit_task
task_class.apply_async(task_args, task_id=task_id)
File “/edx/app/edxapp/edx-platform/lms/djangoapps/instructor_task/tasks.py”, riga 80, in rescore_problem
return run_main_task(entry_id, visit_fcn, action_name)
File "/edx/app/edxapp/edx-platform/lms/djangoapps/instructor_task/tasks_helper.py", riga 279, in run_main_task
task_progress = task_fcn(entry_id, course_id, task_input, action_name)
File”/edx/app/edxapp/edx-platform/lms/djangoapps/instructor_task/tasks_helper.py”, riga 345, in perform_module_state_update
moduli_da_aggiornare = StudentModule.objects.filter(id_corso=id_corso, chiave_stato_modulo__in=chiavi_uso)
Durante lo sviluppo della libreria Call Stack Manager, ho dovuto risolvere numerosi problemi di base a livello di Python come la gestione efficace delle classi Django Model, la creazione di classi Django Model in fase di esecuzione a scopo di test, il wrapping delle funzioni in modo che non perdano la loro identità , gestendo scontri con altri decoratori come @contrarre in PyContracts e molti altri.
Chiama Stack Manager come libreria generale
Lo scopo principale del Call Stack Manager era di tenere traccia delle chiamate Modulo Studente e StudentModuleHistory. Inoltre, possiamo tracciare qualsiasi funzione Python a qualsiasi livello particolare di codice. Il monitoraggio può essere interrotto quando necessario. Con l'uso di questa libreria, possiamo deprecare efficacemente le funzioni indesiderate monitorando le chiamate sconosciute. Sarà interessante perseguire lo sviluppo di questo strumento come strumento generico applicabile a qualsiasi progetto Django.
Conclusione
Credo fermamente che la soluzione generalizzata di Call Stack Manager possa essere utilizzata come plugin o libreria standard per il progetto Django/Python con ulteriori aggiunte e modifiche.
Ripensando alla mia esperienza di tirocinio, mi è piaciuto lavorare sulla base di codice edX. Lavorare su un progetto open source su larga scala che ha un enorme impatto globale è molto eccitante. EdX ha un team di programmatori fantastici e ha trattato gli stagisti come dipendenti a tempo pieno con la massima visibilità a tutti i livelli. Mi sono ritrovato a lavorare su tecnologie all'avanguardia e ho partecipato a tutti i tipi di discussioni tecniche con il team della piattaforma. Lavorare al livello base di Python e risolvere problemi insoliti e inaspettati è stato particolarmente gratificante. Vorrei ringraziare John Eskew, Calen Pennington, Ali Mohammad, Brian Beggs, Miki Goyal, Adam Palay e Ned Batchelder per il loro continuo aiuto e supporto. Lavorare in edX è stata un'opportunità affascinante e stimolante che apprezzerò per gli anni a venire.
![]()