denyAccessUnlessGranted('ROLE_ADMIN'); $state = $this->scheduler->fastState(); return $this->render('admin/tasks.html.twig', [ 'tasks' => $this->scheduler->overview(), 'traffic' => $state['traffic'], 'admin' => $state['admin'], 'next' => $state['next'], 'now' => gmdate('Y-m-d H:i:s'), 'protocol' => $this->scheduler->protocol(30), // Der Schlüssel für einen URL-Cronjob. Er steht in keiner Datenbank: er wird aus dem // Anwendungsgeheimnis abgeleitet, ist damit auf jedem Server ein anderer und ändert // sich, wenn das Geheimnis gewechselt wird. 'cronUrl' => $this->generateUrl('cms_cron', ['token' => Scheduler::cronToken($this->secret)], UrlGeneratorInterface::ABSOLUTE_URL), ]); } #[Route('/%kant.admin_path%/aufgaben/ausfuehren', name: 'admin_tasks_run', methods: ['POST'])] public function run(Request $request): Response { $this->denyAccessUnlessGranted('ROLE_ADMIN'); if (!$this->isCsrfTokenValid('tasks', $request->request->getString('_csrf_token'))) { return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.'); } @set_time_limit(0); $result = $this->scheduler->runNow($request->request->getString('name')); if (null === $result) { return $this->back('Diese Aufgabe gibt es nicht oder sie läuft gerade schon.'); } $this->addFlash('ok' === $result['status'] ? 'success' : 'error', sprintf( '%s: %s (%d ms)', $result['label'], $result['message'], $result['ms'], )); return $this->redirectToRoute('admin_tasks'); } /** * Abstand, Ein/Aus je Aufgabe und die beiden Auslöser, die in Anfragen stecken. * * Ein Formular für alles, weil es eine Entscheidung ist: wie dieser Server seine Aufgaben * abarbeitet. Zwei getrennte Formulare hätten zwei Speicherknöpfe und dieselbe Wirkung. */ #[Route('/%kant.admin_path%/aufgaben/einstellen', name: 'admin_tasks_configure', methods: ['POST'])] public function configure(Request $request): Response { $this->denyAccessUnlessGranted('ROLE_ADMIN'); if (!$this->isCsrfTokenValid('tasks', $request->request->getString('_csrf_token'))) { return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.'); } $this->scheduler->setWorkers( $request->request->getBoolean('traffic'), $request->request->getBoolean('admin'), ); $enabled = $request->request->all('enabled'); foreach ($request->request->all('interval') as $name => $minutes) { $name = (string) $name; $this->scheduler->setInterval($name, max(1, (int) $minutes) * 60); $this->scheduler->enable($name, isset($enabled[$name])); } $this->addFlash('success', 'Der Plan ist gespeichert.'); return $this->redirectToRoute('admin_tasks'); } /** Eine Sperre, die stehen geblieben ist, weil das Hosting den Prozess mitten im Lauf beendet hat. */ #[Route('/%kant.admin_path%/aufgaben/freigeben', name: 'admin_tasks_release', methods: ['POST'])] public function release(Request $request): Response { $this->denyAccessUnlessGranted('ROLE_ADMIN'); if (!$this->isCsrfTokenValid('tasks', $request->request->getString('_csrf_token'))) { return $this->back('Deine Sitzung ist abgelaufen. Bitte melde dich erneut an.'); } $this->scheduler->release($request->request->getString('name')); $this->addFlash('success', 'Die Sperre ist aufgehoben. Die Aufgabe darf wieder starten.'); return $this->redirectToRoute('admin_tasks'); } /** * Der Takt der geöffneten Verwaltung. * * Damit läuft der Plan auch auf einer Website, die gerade niemand besucht – solange jemand im * Backend arbeitet. Das Skript fragt nur, während der Reiter sichtbar ist; ein im Hintergrund * vergessener Reiter soll keine Sitzung endlos offen halten. * * Die Grenzen sind hier großzügiger als beim Besuch: hier wartet niemand auf eine Seite. */ #[Route('/%kant.admin_path%/aufgaben/takt', name: 'admin_tasks_tick', methods: ['POST'])] public function tick(Request $request): JsonResponse { $this->denyAccessUnlessGranted('ROLE_EDITOR'); if (!$this->isCsrfTokenValid('tasks-tick', $request->request->getString('_csrf_token'))) { return new JsonResponse(['error' => 'token'], Response::HTTP_FORBIDDEN); } $request->attributes->set(TaskWorkerSubscriber::HANDLED, true); $state = $this->scheduler->fastState(); if (!$state['admin']) { return new JsonResponse(['off' => true, 'ran' => []]); } // Anheben, nicht senken: auf einem Prozess ohne Grenze waere 120 eine neue Grenze. $limit = (int) ini_get('max_execution_time'); if ($limit > 0 && $limit < 120) { @set_time_limit(120); } $ran = $this->scheduler->runDue('verwaltung', 3, 45); return new JsonResponse([ 'ran' => $ran, 'next' => $this->scheduler->fastState()['next'], ]); } private function back(string $error): Response { $this->addFlash('error', $error); return $this->redirectToRoute('admin_tasks'); } }