PostgreSQLLa base de données la plus sophistiquée au monde.

Version anglaise

45. Processus en tâche de fond (background worker)

PostgreSQL peut être étendu pour lancer du code utilisateur dans des processus séparés. Ces processus sont démarrés, arrêtés et supervisés par postgres, ce qui leur permet d'avoir un cycle de vie étroitement lié au statut du serveur. Ces processus ont des options pour s'attacher à la zone de mémoire partagée de PostgreSQL™ et pour se connecter aux bases de manière interne ; ils peuvent également exécuter de multiples transactions séquentiellement, comme n'importe quel processus client standard connecté au serveur. De plus, en se liant avec la bibliothèque libpq, ils peuvent se connecter au serveur et se comporter comme une application cliente standard.

[Avertissement]

Avertissement

Il y a de considérables risques de robustesse et sécurité lorsque l'on utilise des processus background worker. En effet, ceux-ci étant écrit en langage C, ils ont un accès total aux données. Les administrateurs désirant activer des modules incluant des processus background worker devraient prendre énormément de précautions. Seuls les modules soigneusement testés devraient être autorisés à lancer des processus background worker.

Seuls les modules listés dans shared_preload_library peuvent démarrer des background workers. Un module désirant démarrer un background worker doit l'enregistrer en appelant RegisterBackgroundWorker(BackgroundWorker *worker) dans son _PG_init(). La structure BackgroundWorker est définie ainsi :

typedef void (*bgworker_main_type)(Datum main_arg);
typedef struct BackgroundWorker
{
    char        bgw_name[BGW_MAXLEN];
    int         bgw_flags;
    BgWorkerStartTime bgw_start_time;
    int         bgw_restart_time;       /* in seconds, or BGW_NEVER_RESTART */
    bgworker_main_type bgw_main;
    Datum       bgw_main_arg;
} BackgroundWorker;

bgw_name est une chaîne de caractères à utiliser dans les messages de trace, liste de processus et autres listes similaires.

bgw_flags est un masque de bit OR indiquant les capacités que veut le module. Les valeurs possibles sont BGWORKER_SHMEM_ACCESS (demandant un accès à la mémoire partagée) et BGWORKER_BACKEND_DATABASE_CONNECTION (demandant la capacité d'établir une connexion à la base, grâce à laquelle il pourra exécuter des transactions et requêtes ultérieurement). Un processus en tâche de fond utilisant BGWORKER_BACKEND_DATABASE_CONNECTION pour se connecter à une base de données doit aussi attacher de la mémoire partagée en utilisant BGWORKER_SHMEM_ACCESS. Dans le cas contraire, le démarrage de la tâche de fond échouera.

bgw_start_time spécifie l'état du serveur dans lequel postgres devrait démarrer le processus ; les valeurs possibles sont BgWorkerStart_PostmasterStart (démarrer dès que postgres lui-même a fini sa propre initialisation ; les processus réclamant celà ne sont pas éligibles à une connexion à la base de données), BgWorkerStart_ConsistentState (démarrer dès qu'un état cohérent a été atteint sur un serveur esclave en lecture seule, permettant aux processus de se connecter aux bases et d'exécuter des requêtes en lecture seule), et BgWorkerStart_RecoveryFinished (démarrer dès que le système est entré dans un état de lecture-écriture normal). Notez que les deux dernières valeurs sont équivalentes sur un serveur qui n'est pas un esclave en lecture seule. Notez également que ces valeurs indiquent uniquement quand les processus doivent être démarrés ; ils ne s'arrêtent pas quand un état différent est atteint.

bgw_restart_time est un intervalle, en secondes, que postgres doit attendre avant de redémarrer un processus, si celui-ci a subi un arrêt brutal. Cet intervalle peut être une valeur positive ou BGW_NEVER_RESTART, indiquant de ne pas redémarrer le processus suite à un arrêt brutal.

bgw_main est un pointeur vers la fonction à lancer quand le processus est démarré. Cette fonction doit prendre un unique argument de type Datum et retourner void. bgw_main_arg lui sera passé comme unique argument. Notez que la variable globale MyBgworkerEntry pointe vers une copie de la structure BackgroundWorker passée lors de l'enregistrement.

Une fois démarré, le processus peut se connecter à une base en appelant BackgroundWorkerInitializeConnection(char *dbname, char *username). Cela autorise le processus à exécuter des transactions et des requêtes en utilisant l'interface SPI. Si dbname vaut NULL, la session n'est pas connectée à une base en particulier, mais les catalogues partagés peuvent être accédés. Si username vaut NULL, le processus sera démarré avec le super utilisateur créé durant initdb. BackgroundWorkerInitializeConnection ne peut être appelé qu'une fois par processus background, il n'est donc pas possible de changer de base de données.

Les signaux sont initialement bloqués jusqu'à ce que le contrôle atteigne la fonction bgw_main, et doivent être débloqués par elle ; cela permet une personnalisation des gestionnaires de signaux du processus, si nécessaire. Les signaux peuvent être débloqués dans le nouveau processus en appellant BackgroundWorkerUnblockSignals et bloqués en appelant BackgroundWorkerBlockSignals.

Les background workers devraient tourner continuellement ; s'ils terminent proprement, postgres les redémarrera immédiatement. Essayez d'utiliser des pauses interruptibles quand ils n'ont rien à faire ; cela peut être effectué en appelant WaitLatch(). Vérifiez que le drapeau WL_POSTMASTER_DEATH est positionné lors de l'appel à cette fonction, et vérifiez le code retour pour une sortie rapide dans le cas d'urgence où postgres lui-même se termine.

Le module contrib worker_spi contient un exemple fonctionnel, qui démontre quelques techniques utiles.