Projet

Général

Profil

Bug #18519

cron qui s'emballe

Ajouté par Thomas Noël il y a plus de 6 ans. Mis à jour il y a plus de 5 ans.

Statut:
Fermé
Priorité:
Normal
Assigné à:
-
Version cible:
-
Début:
07 septembre 2017
Echéance:
% réalisé:

0%

Temps estimé:
Patch proposed:
Oui
Planning:

Description

Vu sur auquo.entrouvert.org :

root     10672  0.0  0.0  61300  1552 ?        S    17:00   0:00  \_ /usr/sbin/CRON -f
wcs      10674  0.0  0.0   4284   636 ?        Ss   17:00   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      10677  0.0  0.0   4284   684 ?        S    17:00   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      10685 36.8  1.4 347716 185548 ?       R    17:00   5:03  |           \_ python /usr/lib/wcs/manage.py cron
root     11390  0.0  0.0  61300  1552 ?        S    17:01   0:00  \_ /usr/sbin/CRON -f
wcs      11391  0.0  0.0   4284   640 ?        Ss   17:01   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      11392  0.0  0.0   4284   688 ?        S    17:01   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      11394  0.3  0.6 167236 75756 ?        S    17:01   0:02  |           \_ python /usr/lib/wcs/manage.py cron
root     11685  0.0  0.0  61300  1552 ?        S    17:02   0:00  \_ /usr/sbin/CRON -f
wcs      11687  0.0  0.0   4284   644 ?        Ss   17:02   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      11689  0.0  0.0   4284   684 ?        S    17:02   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      11692  0.5  0.6 167236 75748 ?        S    17:02   0:03  |           \_ python /usr/lib/wcs/manage.py cron
root     11984  0.0  0.0  61300  1552 ?        S    17:03   0:00  \_ /usr/sbin/CRON -f
wcs      11985  0.0  0.0   4284   644 ?        Ss   17:03   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      11986  0.0  0.0   4284   684 ?        S    17:03   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      11988  0.4  0.6 167236 75752 ?        S    17:03   0:02  |           \_ python /usr/lib/wcs/manage.py cron
root     12353  0.0  0.0  61300  1552 ?        S    17:04   0:00  \_ /usr/sbin/CRON -f
wcs      12355  0.0  0.0   4284   640 ?        Ss   17:04   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      12357  0.0  0.0   4284   684 ?        S    17:04   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      12360  0.5  0.6 167236 75748 ?        S    17:04   0:03  |           \_ python /usr/lib/wcs/manage.py cron
root     12627  0.0  0.0  61300  1552 ?        S    17:05   0:00  \_ /usr/sbin/CRON -f
wcs      12629  0.0  0.0   4284   644 ?        Ss   17:05   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      12630  0.0  0.0   4284   688 ?        S    17:05   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      12632  0.6  0.6 167236 75752 ?        S    17:05   0:03  |           \_ python /usr/lib/wcs/manage.py cron
root     13170  0.0  0.0  61300  1552 ?        S    17:06   0:00  \_ /usr/sbin/CRON -f
wcs      13172  0.0  0.0   4284   640 ?        Ss   17:06   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      13174  0.0  0.0   4284   684 ?        S    17:06   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      13178  0.6  0.6 167236 75748 ?        S    17:06   0:03  |           \_ python /usr/lib/wcs/manage.py cron
root     13349  0.0  0.0  61300  1552 ?        S    17:07   0:00  \_ /usr/sbin/CRON -f
wcs      13350  0.0  0.0   4284   644 ?        Ss   17:07   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      13351  0.0  0.0   4284   688 ?        S    17:07   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      13353  0.8  0.6 167236 75752 ?        S    17:07   0:03  |           \_ python /usr/lib/wcs/manage.py cron
root     13662  0.0  0.0  61300  1552 ?        S    17:08   0:00  \_ /usr/sbin/CRON -f
wcs      13664  0.0  0.0   4284   640 ?        Ss   17:08   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      13665  0.0  0.0   4284   684 ?        S    17:08   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      13669  0.8  0.6 167236 75756 ?        S    17:08   0:03  |           \_ python /usr/lib/wcs/manage.py cron
root     13868  0.0  0.0  61300  1552 ?        S    17:09   0:00  \_ /usr/sbin/CRON -f
wcs      13869  0.0  0.0   4284   640 ?        Ss   17:09   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      13870  0.0  0.0   4284   684 ?        S    17:09   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      13872  1.1  0.6 167236 75752 ?        S    17:09   0:03  |           \_ python /usr/lib/wcs/manage.py cron
root     14226  0.0  0.0  61300  1552 ?        S    17:10   0:00  \_ /usr/sbin/CRON -f
wcs      14228  0.0  0.0   4284   640 ?        Ss   17:10   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      14229  0.0  0.0   4284   684 ?        S    17:10   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      14233  1.3  0.6 167236 75756 ?        S    17:10   0:02  |           \_ python /usr/lib/wcs/manage.py cron
root     14828  0.0  0.0  61300  1552 ?        S    17:11   0:00  \_ /usr/sbin/CRON -f
wcs      14829  0.0  0.0   4284   640 ?        Ss   17:11   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      14830  0.0  0.0   4284   684 ?        S    17:11   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      14832  1.6  0.6 167236 75752 ?        S    17:11   0:02  |           \_ python /usr/lib/wcs/manage.py cron
root     15142  0.0  0.0  61300  1552 ?        S    17:12   0:00  \_ /usr/sbin/CRON -f
wcs      15143  0.0  0.0   4284   644 ?        Ss   17:12   0:00  |   \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      15145  0.0  0.0   4284   684 ?        S    17:12   0:00  |       \_ /bin/sh /usr/bin/wcs-manage cron
wcs      15149  2.9  0.6 167236 75752 ?        S    17:12   0:03  |           \_ python /usr/lib/wcs/manage.py cron
root     15340  0.0  0.0  61300  1552 ?        S    17:13   0:00  \_ /usr/sbin/CRON -f
wcs      15341  0.0  0.0   4284   640 ?        Ss   17:13   0:00      \_ /bin/sh -c /usr/bin/wcs-manage cron
wcs      15342  0.0  0.0   4284   688 ?        S    17:13   0:00          \_ /bin/sh /usr/bin/wcs-manage cron
wcs      15344  6.1  0.6 167236 75752 ?        S    17:13   0:02              \_ python /usr/lib/wcs/manage.py cron

Comme le cron est lancé toute les minutes et ne vérifie par qu'un autre cron est en cours, on a jusqu'à 15 cron lancés en parallèle (quand on tombe sur des cron qui gère des centaines d'expiration à vérifier).

Mais si on lock, un seul workflow lent pourra bloquer toute la mécanique pendant un gros bout de temps.


Fichiers

Révisions associées

Révision 5b582638 (diff)
Ajouté par Thomas Noël il y a environ 6 ans

don't start a new cron if locked (#18519)

Historique

#1

Mis à jour par Thomas Noël il y a plus de 6 ans

Idées en vrac :
  • lancer un process "cron" par instance
  • voire un process par formdef
#2

Mis à jour par Benjamin Dauvergne il y a plus de 6 ans

Utiliser systemd:

wcs-cron.service

[Unit]
Description=w.c.s. cron

[Service]
ExecStart=/usr/bin/wcs-manage cron

wcs-cron.timer

[Unit]
Description=w.c.s. cron

[Timer]
OnCalendar=*-*-* *:*:*
AccuracySec=1 minute

#3

Mis à jour par Benjamin Dauvergne il y a plus de 6 ans

systemd ne lance la commande qu'une fois et attend qu'elle termine par défaut.

#4

Mis à jour par Thomas Noël il y a plus de 6 ans

Je propose déjà de ne pas lancer un nouveau cron si le lock est présent (actuellement on attend que le lock se libère)

#5

Mis à jour par Thomas Noël il y a plus de 6 ans

Ensuite j'imaginerai bien un multiprocessing.pool qui itère sur les tenants, afin d'avoir un process par tenant, genre (poc/wip absolument pas testé) :

import tempfile
import time
import os
import multiprocessing.pool

from django.core.management.base import BaseCommand
from qommon.publisher import get_publisher_class

from qommon import get_logger
from qommon.vendor import locket
from qommon.cron import cron_worker

def launch_cron(context):
    publisher = context['publisher']
    app_dir = context['app_dir']
    hostname = context['hostname']
    now = context['now']
    publisher.app_dir = os.path.join(app_dir, hostname)
    cron_worker(publisher, now)

class Command(BaseCommand):
    help = 'Execute cronjobs'

    def handle(self, verbosity, **options):
        lockfile = os.path.join(tempfile.gettempdir(), 'wcs-cron-in-progress.lock')
        try:
            with locket.lock_file(lockfile, timeout=0):
                now = time.localtime()
                publisher_class = get_publisher_class()
                publisher_class.register_cron = True
                publisher = publisher_class.create_publisher()
                app_dir = publisher.app_dir

                contexts = []
                for hostname in publisher.get_tenants():
                    contexts.append({
                        'publisher': publisher,
                        'app_dir': app_dir,
                        'hostname': hostname,
                        'now': now,
                    })

                pool = multiprocessing.pool.ThreadPool()
                try:
                    list(pool.imap_unordered(launch_cron, contexts))
                finally:
                    pool.close()
                    pool.terminate()

        except locket.LockError:
            get_logger().warn('can not start cron job - locked by %s' % lockfile)
#6

Mis à jour par Thomas Noël il y a environ 6 ans

Dans l'idée de granulariser plus, tout en lockant mieux, un patch qui lance les cron en parallèle, avec chacun son lock (c'est un draft, ça met plein de lock dans /var/lib/wcs/site/, pas super joli).

Ca permettrait de mieux gérer les opération lourdes telles que les reindexations fts, sans (trop) bloquer le reste.

Par défaut ça lance autant de cron que de coeurs sur la machine, et donc on serait quand même bloqués si on a plus de sites que de coeurs, on pourrait ne pas avoir cette limite, voire même catégoriser deux familles de cron, ceux qui peuvent être lancés "tous en parallèle" (genre les sauts) et ceux qu'on limite au nombre de coeurs (reindexation fts).

#8

Mis à jour par Thomas Noël il y a environ 6 ans

Retour dans le passé, sur l'objet de départ du ticket, à savoir des crons qui s'attendent les uns les autres... si la durée d'un cron est supérieure à la minute et qu'il est lancé chaque minute (JUMP_TIMEOUT_INTERVAL=60), ça peut vite devenir la cata.

Je reviens donc à ma première proposition, à savoir que le cron abandonne en présence d'un lock. Patch rebasé sur la commande Django, et avec des tests.

(on pense à passer à systemd aussi, mais pour l'instant on n'a pas de solution pour concilier les deux, or il faut continuer à gérer les machines sans systemd)

#9

Mis à jour par Emmanuel Cazenave il y a environ 6 ans

  • il me semble qu'on a pas besoin pas besoin d'appeler super(Command, self).add_arguments(parser)
  • pas très fan du fait que l'option de verbosité ait un impact sur l'exit code du processus. Je trouverai plus propre si une autre option (--fail-if-lock ?) déclenchait l'exception en cas de lock.
  • en parlant de verbosité pour faciliter l'analyse, puisque le cron peut durer et que ça commence à poser problème, peut être afficher sur stdout à quel tenant en est le cron, avec un compteur (genre "demarches-fondettes.xxxx.yyyy 6/40) ?
#10

Mis à jour par Thomas Noël il y a environ 6 ans

Yep pour tout. J'ai donc juste posé des print selon la verbosité, y compris à la place du CommandError.

#11

Mis à jour par Emmanuel Cazenave il y a environ 6 ans

si je pinaille je dirais que tu n'as pas mis le compteur qui dirait combien de tenant on a déjà fait et combien il reste à faire, mais je te laisse juger, ack.

#12

Mis à jour par Thomas Noël il y a environ 6 ans

  • Statut changé de En cours à Résolu (à déployer)
commit 5b582638d532c65a419c561a87ab7263ab8fd5a9
Author: Thomas NOEL <tnoel@entrouvert.com>
Date:   Fri Mar 23 18:47:42 2018 +0100

    don't start a new cron if locked (#18519)

#13

Mis à jour par Frédéric Péters il y a plus de 5 ans

  • Statut changé de Résolu (à déployer) à Solution déployée

Formats disponibles : Atom PDF