I loop di eventi in più lingue non sono del tutto impossibili, ma se segui questa strada ti trovi in un mondo di dolore. Solo questo esclude alcune soluzioni come i binding di lingua generati automaticamente.
L'unico modo semplice per collegare due linguaggi di programmazione è tramite IPC. Lascia che l'applicazione avvii i plug-in come sottoprocessi e comunichi tramite pipe. In alternativa, implementa la tua applicazione come server a cui i processi separati possono connettersi. Vantaggio aggiunto delle soluzioni basate su IPC: la maggior parte dei loop di eventi facilitano l'attivazione di handle I / O leggibili.
Oltre queste pipe, si scambiano messaggi di qualsiasi formato. Questo potrebbe essere un semplice protocollo "un documento JSON per linea", messaggi Protobuf o HTTP completo. Questa è la parte in cui è possibile scegliere un design facile da implementare per tutti i partecipanti, sia per quanto riguarda la tecnologia di serializzazione dei messaggi sia per il protocollo implementato da questi messaggi.
Il modo in cui il protocollo del plugin deve essere strutturato dipende da cosa dovrebbero fare queste applicazioni. Per esempio. un plugin può essere un filtro che massaggia alcuni dati. Quindi, l'applicazione principale ha un codice come questo:
sendMessageToPlugin(data)
result = await readMessageFromPlugin()
Quindi questa è effettivamente una comunicazione sincrona con il plugin, ma non blocca la tua applicazione. Il plug-in deve ancora rispondere ai messaggi in ordine, ma potrebbe non essere un problema per molti carichi di lavoro.
Un altro caso semplice è quando il plug-in è semplicemente un utente consumer. Quindi basta inviare messaggi al plugin senza dover ricevere alcuna risposta. Ma questo apre alcune domande difficili: cosa succede se ci sono più eventi di quelli che il plugin può attualmente consumare? Come possono essere bufferizzati? Dovrebbero essere tamponati? Cosa succede quando il plug-in si arresta in modo anomalo?
In questi casi più complicati, potrebbe essere ragionevole utilizzare una coda di messaggi esistente che funge da intermediario tra i plug-in e l'applicazione.
È generalmente ragionevole offrire un'API piccola, semplice e ben definita ai plugin. Questo rende impossibile per il plugin richiedere dati arbitrari. Invece, si definiscono i messaggi che contengono i dati necessari. Se hai bisogno di una datamodel condivisa, l'uso di un database esterno può essere sensato perché può fare aggiornamenti atomici e garantisce la coerenza della tua datamodel. I tuoi messaggi contengono quindi le chiavi del database, non i dati completi.
Nota che più il tuo design si evolve in una certa direzione, più diventa facile applicare le migliori pratiche dagli approcci SOA o Microservice. Tutti questi problemi affrontano lo stesso problema: cooperazione indipendente dalla lingua tra più processi.
Vorrei anche sottolineare che queste sfide ingegneristiche, pur non essendo irrisolvibili, richiedono ancora molto impegno. A meno che tu non abbia un bisogno concreto che giustifichi il costo di sviluppo di questo sistema di plugin, potrebbe essere meglio rimanere nella lingua ospite. L'integrazione di una libreria è molto più semplice rispetto all'utilizzo di IPC.