Merge pull request #19972 from gavindsouza/cli-scheduler-status

refactor(cli): Scheduler
This commit is contained in:
Ankush Menat 2023-02-14 18:09:21 +05:30 committed by GitHub
commit c7e1bec0bd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 31 deletions

View file

@ -376,6 +376,7 @@ def serve(
"0.0.0.0",
int(port),
application,
exclude_patterns=["test_*"],
use_reloader=False if in_test_env else not no_reload,
use_debugger=not in_test_env,
use_evalex=not in_test_env,

View file

@ -5,7 +5,6 @@ import click
import frappe
from frappe.commands import get_site, pass_context
from frappe.exceptions import SiteNotSpecifiedError
from frappe.utils import cint
@click.command("trigger-scheduler-event", help="Trigger a scheduler event")
@ -74,36 +73,40 @@ def disable_scheduler(context):
@click.command("scheduler")
@click.option("--site", help="site name")
@click.argument("state", type=click.Choice(["pause", "resume", "disable", "enable"]))
@click.argument("state", type=click.Choice(["pause", "resume", "disable", "enable", "status"]))
@click.option(
"--format", "-f", default="text", type=click.Choice(["json", "text"]), help="Output format"
)
@click.option("--verbose", "-v", is_flag=True, help="Verbose output")
@pass_context
def scheduler(context, state, site=None):
def scheduler(context, state: str, format: str, verbose: bool = False, site: str | None = None):
"""Control scheduler state."""
import frappe.utils.scheduler
from frappe.installer import update_site_config
import frappe
from frappe.utils.scheduler import is_scheduler_inactive, toggle_scheduler
if not site:
site = get_site(context)
site = site or get_site(context)
try:
frappe.init(site=site)
output = {
"text": "Scheduler is {status} for site {site}",
"json": '{{"status": "{status}", "site": "{site}"}}',
}
if state == "pause":
update_site_config("pause_scheduler", 1)
elif state == "resume":
update_site_config("pause_scheduler", 0)
elif state == "disable":
frappe.connect()
frappe.utils.scheduler.disable_scheduler()
frappe.db.commit()
elif state == "enable":
frappe.connect()
frappe.utils.scheduler.enable_scheduler()
frappe.db.commit()
with frappe.init_site(site=site):
match state:
case "status":
frappe.connect()
status = "disabled" if is_scheduler_inactive(verbose=verbose) else "enabled"
return print(output[format].format(status=status, site=site))
case "pause" | "resume":
from frappe.installer import update_site_config
print(f"Scheduler {state}d for site {site}")
update_site_config("pause_scheduler", state == "pause")
case "enable" | "disable":
frappe.connect()
toggle_scheduler(state == "enable")
frappe.db.commit()
finally:
frappe.destroy()
print(output[format].format(status=f"{state}d", site=site))
@click.command("set-maintenance-mode")

View file

@ -33,6 +33,7 @@ from frappe.tests.utils import FrappeTestCase, timeout
from frappe.utils import add_to_date, get_bench_path, get_bench_relative_path, now
from frappe.utils.backups import BackupGenerator, fetch_latest_backups
from frappe.utils.jinja_globals import bundled_asset
from frappe.utils.scheduler import enable_scheduler, is_scheduler_inactive
_result: Result | None = None
TEST_SITE = "commands-site-O4PN2QKA.test" # added random string tag to avoid collisions
@ -773,3 +774,52 @@ class TestDBCli(BaseTestCommands):
def test_db_cli(self):
self.execute("bench --site {site} db-console", kwargs={"cmd_input": rb"\q"})
self.assertEqual(self.returncode, 0)
@run_only_if(db_type_is.MARIADB)
def test_db_cli_with_sql(self):
self.execute("bench --site {site} db-console -e 'select 1'")
self.assertEqual(self.returncode, 0)
self.assertIn("1", self.stdout)
class TestSchedulerCLI(BaseTestCommands):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.is_scheduler_active = not is_scheduler_inactive()
@classmethod
def tearDownClass(cls):
super().tearDownClass()
if cls.is_scheduler_active:
enable_scheduler()
def test_scheduler_status(self):
self.execute("bench --site {site} scheduler status")
self.assertEqual(self.returncode, 0)
self.assertRegex(self.stdout, r"Scheduler is (disabled|enabled) for site .*")
self.execute("bench --site {site} scheduler status -f json")
parsed_output = frappe.parse_json(self.stdout)
self.assertEqual(self.returncode, 0)
self.assertIsInstance(parsed_output, dict)
self.assertIn("status", parsed_output)
self.assertIn("site", parsed_output)
def test_scheduler_enable_disable(self):
self.execute("bench --site {site} scheduler disable")
self.assertEqual(self.returncode, 0)
self.assertRegex(self.stdout, r"Scheduler is disabled for site .*")
self.execute("bench --site {site} scheduler enable")
self.assertEqual(self.returncode, 0)
self.assertRegex(self.stdout, r"Scheduler is enabled for site .*")
def test_scheduler_pause_resume(self):
self.execute("bench --site {site} scheduler pause")
self.assertEqual(self.returncode, 0)
self.assertRegex(self.stdout, r"Scheduler is paused for site .*")
self.execute("bench --site {site} scheduler resume")
self.assertEqual(self.returncode, 0)
self.assertRegex(self.stdout, r"Scheduler is resumed for site .*")

View file

@ -92,31 +92,35 @@ def enqueue_events(site: str) -> list[str] | None:
return enqueued_jobs
def is_scheduler_inactive() -> bool:
def is_scheduler_inactive(verbose=True) -> bool:
if frappe.local.conf.maintenance_mode:
cprint(f"{frappe.local.site}: Maintenance mode is ON")
if verbose:
cprint(f"{frappe.local.site}: Maintenance mode is ON")
return True
if frappe.local.conf.pause_scheduler:
cprint(f"{frappe.local.site}: frappe.conf.pause_scheduler is SET")
if verbose:
cprint(f"{frappe.local.site}: frappe.conf.pause_scheduler is SET")
return True
if is_scheduler_disabled():
if is_scheduler_disabled(verbose=verbose):
return True
return False
def is_scheduler_disabled() -> bool:
def is_scheduler_disabled(verbose=True) -> bool:
if frappe.conf.disable_scheduler:
cprint(f"{frappe.local.site}: frappe.conf.disable_scheduler is SET")
if verbose:
cprint(f"{frappe.local.site}: frappe.conf.disable_scheduler is SET")
return True
scheduler_disabled = not frappe.utils.cint(
frappe.db.get_single_value("System Settings", "enable_scheduler")
)
if scheduler_disabled:
cprint(f"{frappe.local.site}: SystemSettings.enable_scheduler is UNSET")
if verbose:
cprint(f"{frappe.local.site}: SystemSettings.enable_scheduler is UNSET")
return scheduler_disabled