-
Notifications
You must be signed in to change notification settings - Fork 2
feat: Composite startup verbs for the flagsmith entrypoint #240
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
96d73e5
c57c5ec
5def409
02f363b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,79 @@ | ||||||||||||||||||||||||||||||||||
| """Composite startup verbs for the `flagsmith` entrypoint. | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| These mirror the sequencing that Core API's `run-docker.sh` performed in | ||||||||||||||||||||||||||||||||||
| shell, but run in a single process so the Django boot cost is paid once. | ||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||
| import shlex | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| from django.conf import settings | ||||||||||||||||||||||||||||||||||
| from django.core.management import ( | ||||||||||||||||||||||||||||||||||
| execute_from_command_line as django_execute_from_command_line, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| WAIT_FOR_MIGRATIONS_TIMEOUT_SECONDS = 30 | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def _wait_for_db( | ||||||||||||||||||||||||||||||||||
| *, | ||||||||||||||||||||||||||||||||||
| wait_for_migrations: bool = False, | ||||||||||||||||||||||||||||||||||
| database: str = "default", | ||||||||||||||||||||||||||||||||||
| wait_for: int | None = None, | ||||||||||||||||||||||||||||||||||
| ) -> None: | ||||||||||||||||||||||||||||||||||
| if os.environ.get("SKIP_WAIT_FOR_DB"): | ||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||
| args = ["waitfordb", "--database", database] | ||||||||||||||||||||||||||||||||||
| if wait_for is not None: | ||||||||||||||||||||||||||||||||||
| args += ["--waitfor", str(wait_for)] | ||||||||||||||||||||||||||||||||||
| if wait_for_migrations: | ||||||||||||||||||||||||||||||||||
| args.append("--migrations") | ||||||||||||||||||||||||||||||||||
| django_execute_from_command_line(["flagsmith", *args]) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def _migrate() -> None: | ||||||||||||||||||||||||||||||||||
| _wait_for_db() | ||||||||||||||||||||||||||||||||||
| databases: list[str] = getattr(settings, "FLAGSMITH_MIGRATE_DATABASES", ["default"]) | ||||||||||||||||||||||||||||||||||
| for database in databases: | ||||||||||||||||||||||||||||||||||
| django_execute_from_command_line( | ||||||||||||||||||||||||||||||||||
| ["flagsmith", "migrate", "--database", database] | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| django_execute_from_command_line(["flagsmith", "createcachetable"]) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def migrate(argv: list[str], *, prog: str) -> None: | ||||||||||||||||||||||||||||||||||
| """Migrate the configured databases, then create the cache table.""" | ||||||||||||||||||||||||||||||||||
| if argv: | ||||||||||||||||||||||||||||||||||
| django_execute_from_command_line(["flagsmith", "migrate", *argv]) | ||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||
| _migrate() | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def serve(argv: list[str], *, prog: str) -> None: | ||||||||||||||||||||||||||||||||||
| """Wait for the database, then start the API server.""" | ||||||||||||||||||||||||||||||||||
| _wait_for_db() | ||||||||||||||||||||||||||||||||||
| django_execute_from_command_line(["flagsmith", "start", "api", *argv]) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def run_task_processor(argv: list[str], *, prog: str) -> None: | ||||||||||||||||||||||||||||||||||
| """Migrate, wait for migrations to be applied, then start the task processor.""" | ||||||||||||||||||||||||||||||||||
| _migrate() | ||||||||||||||||||||||||||||||||||
| databases: list[str] = getattr( | ||||||||||||||||||||||||||||||||||
| settings, "FLAGSMITH_WAIT_FOR_MIGRATIONS_DATABASES", ["default"] | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| for database in databases: | ||||||||||||||||||||||||||||||||||
| _wait_for_db( | ||||||||||||||||||||||||||||||||||
| wait_for_migrations=True, | ||||||||||||||||||||||||||||||||||
| database=database, | ||||||||||||||||||||||||||||||||||
| wait_for=WAIT_FOR_MIGRATIONS_TIMEOUT_SECONDS, | ||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||
| django_execute_from_command_line(["flagsmith", "start", "task-processor", *argv]) | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| def migrate_and_serve(argv: list[str], *, prog: str) -> None: | ||||||||||||||||||||||||||||||||||
| """Migrate, run any configured startup commands, then start the API server.""" | ||||||||||||||||||||||||||||||||||
| _migrate() | ||||||||||||||||||||||||||||||||||
| startup_commands: list[str] = getattr(settings, "FLAGSMITH_STARTUP_COMMANDS", []) | ||||||||||||||||||||||||||||||||||
| for command in startup_commands: | ||||||||||||||||||||||||||||||||||
| django_execute_from_command_line(["flagsmith", *shlex.split(command)]) | ||||||||||||||||||||||||||||||||||
| django_execute_from_command_line(["flagsmith", "start", "api", *argv]) | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+73
to
+79
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a startup command in
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,11 +4,15 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||
| from contextlib import contextmanager | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| from typing import Any, Generator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| from environs import Env | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| from task_processor.threads import TaskRunnerCoordinator | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| from task_processor.types import TaskCallable, TaskProcessorConfig | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| logger = logging.getLogger(__name__) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| env = Env() | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| def get_task_identifier_from_function( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| function: TaskCallable[Any], | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -24,25 +28,28 @@ def add_arguments(parser: argparse.ArgumentParser) -> None: | |||||||||||||||||||||||||||||||||||||||||||||||||||
| "--numthreads", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| type=int, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| help="Number of worker threads to run.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=5, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=env.int("TASK_PROCESSOR_NUM_THREADS", 5), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| parser.add_argument( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--sleepintervalms", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| type=int, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| help="Number of millis each worker waits before checking for new tasks", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=2000, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=env.int( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "TASK_PROCESSOR_SLEEP_INTERVAL_MS", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| env.int("TASK_PROCESSOR_SLEEP_INTERVAL", 500), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
33
to
41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The legacy environment variable
We should parse
Suggested change
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| parser.add_argument( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--graceperiodms", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| type=int, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| help="Number of millis before running task is considered 'stuck'.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=20000, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=env.int("TASK_PROCESSOR_GRACE_PERIOD_MS", 20000), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| parser.add_argument( | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| "--queuepopsize", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| type=int, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| help="Number of tasks each worker will pop from the queue on each cycle.", | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=10, | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| default=env.int("TASK_PROCESSOR_QUEUE_POP_SIZE", 10), | ||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Clarify that
TASK_PROCESSOR_SLEEP_INTERVALis configured in seconds.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #240 (comment)