diff --git a/README.md b/README.md index 8ac6d9909a..351c4e90e2 100644 --- a/README.md +++ b/README.md @@ -843,29 +843,22 @@ Alternatively this can be done outside of docker by running: # Background tasks & worker -Iaso queue certain functions (task) for later execution, so they can run -outside an HTTP request. This is used for functions that take a long time to execute, -so they don't canceled in the middle by a timeout of a connection closed. -e.g: bulk import, modifications or export of OrgUnits. Theses are the functions -marked by the decorator @task_decorator, when called they get added to a Queue -and get executed by a worker. +Iaso queues certain functions (tasks) for later execution, so they can run outside an HTTP request. This is used for functions that take a long time to execute, so they're not canceled in the middle by a timeout of a connection closed. +Examples include: bulk import, modifications or export of OrgUnits. +These functions are marked by the decorator `@task_decorator`. When called, they get added to a Queue and get executed by a worker. In local development, you can run a worker by using the command: + ``` docker-compose run iaso manage tasks_worker ``` Alternatively, you can call the url `tasks/run_all` which will run all the pending tasks in queue. -If you want to develop a new background task, the endpoint `/api/copy_version/` -is a good example of how to create a task and to plug it to the api. +If you want to develop a new background task, the endpoint `/api/copy_version/` is a good example of how to create a task and to plug it to the api. -To call a function with the @task decorator, you need to pass it a User objects, in addition to -the other function's arguments, this arg represent which user is launching -the task. At execution time the task will receive a iaso.models.Task -instance in argument that should be used to report progress. It's -mandatory for the function, at the end of a successful execution to call -task.report_success() to mark its proper completion. +To call a function with the `@task_decorator`, you need to pass it a `User` object, in addition to the other function's arguments. The user argument represents the user that is launching the task. At execution time the task will receive a `iaso.models.Task` instance as an argument that can be used to report progress. It's +mandatory for the function to call `task.report_success()` at the end of a successful execution to mark its proper completion. We have two background workers mechanisms: a postgres backed one, and a SQS backed one. You can choose which one to use with the `BACKGROUND_TASK_SERVICE` environment variable, use either `SQS` or `POSTGRES` (it defaults to `SQS` in production). @@ -877,6 +870,6 @@ In production on AWS, we use Elastic Beanstalk workers which use a SQS queue. Th ## Postgres -This is also the one that you get when running locally with `docker-compose run iaso manage tasks_worker`, instead of enqueuing the tasks to SQS, we now enqueue them to our postgres server. +This is the one you get when running locally with `docker-compose run iaso manage tasks_worker`. Instead of enqueuing the tasks to SQS, we enqueue them to our postgres server. -Our tasks_worker process (which runs indefinitely) will listen for new tasks and run them when it gets notified (using PostgreSQL NOTIFY/LISTEN features) +Our `tasks_worker` process (which runs indefinitely) will listen for new tasks and run them when it gets notified (using PostgreSQL NOTIFY/LISTEN features). diff --git a/hat/assets/js/apps/Iaso/domains/app/components/messages.js b/hat/assets/js/apps/Iaso/domains/app/components/messages.js index 90457ce728..200ba2903f 100644 --- a/hat/assets/js/apps/Iaso/domains/app/components/messages.js +++ b/hat/assets/js/apps/Iaso/domains/app/components/messages.js @@ -22,7 +22,7 @@ const MESSAGES = defineMessages({ id: 'iaso.tooltip.viewUserManual', }, iasoVersion: { - defautMessage: 'App version', + defaultMessage: 'App version', id: 'iaso.label.iasoVersion', }, }); diff --git a/hat/assets/js/apps/Iaso/domains/dataSources/messages.js b/hat/assets/js/apps/Iaso/domains/dataSources/messages.js index 9b86050d4b..813875e4b0 100644 --- a/hat/assets/js/apps/Iaso/domains/dataSources/messages.js +++ b/hat/assets/js/apps/Iaso/domains/dataSources/messages.js @@ -307,7 +307,7 @@ const MESSAGES = defineMessages({ id: 'iaso.snackBar.importFromDhis2Success', }, importFromDhis2Error: { - defaulteEssage: 'An error occurred while importing from DHIS2', + defaultMessage: 'An error occurred while importing from DHIS2', id: 'iaso.snackBar.importFromDhis2Error', }, exportToDhis2Success: { @@ -323,15 +323,15 @@ const MESSAGES = defineMessages({ id: 'iaso.snackBar.importGpkgSuccess', }, importGpkgError: { - defaultMEssage: 'An error occurred while importing the gpkg file', + defaultMessage: 'An error occurred while importing the gpkg file', id: 'iaso.snackBar.importGpkgError', }, checkDhis2Success: { - defaultMEssage: 'Connection to server ok', + defaultMessage: 'Connection to server ok', id: 'iaso.dataSources.checkDHIS2.success', }, checkDhis2Error: { - defaultMEssage: 'Connection Error check settings', + defaultMessage: 'Connection Error check settings', id: 'iaso.dataSources.checkDHIS2.error', }, newEmptyVersionSavedSuccess: { diff --git a/iaso/api/completeness_stats.py b/iaso/api/completeness_stats.py index 12bb62135b..bae4ad5521 100644 --- a/iaso/api/completeness_stats.py +++ b/iaso/api/completeness_stats.py @@ -390,12 +390,10 @@ def to_dict(row_ou: OrgUnitWithFormStat): return { "name": row_ou.name, "id": row_ou.id, - "org_unit": row_ou.as_dict_for_completeness_stats(), + "org_unit": row_ou.as_minimal_dict(), "form_stats": row_ou.form_stats, - "org_unit_type": row_ou.org_unit_type.as_dict_for_completeness_stats() if row_ou.org_unit_type else {}, - "parent_org_unit": ( - row_ou.parent.as_dict_for_completeness_stats_with_parent() if row_ou.parent else None - ), + "org_unit_type": row_ou.org_unit_type.as_minimal_dict() if row_ou.org_unit_type else {}, + "parent_org_unit": row_ou.parent.as_minimal_dict_with_parent() if row_ou.parent else None, "has_children": has_children(row_ou), } @@ -409,10 +407,8 @@ def to_map(row_ou: OrgUnitWithFormStat): "latitude": row_ou.location.y if row_ou.location else None, "longitude": row_ou.location.x if row_ou.location else None, "altitude": row_ou.location.z if row_ou.location else None, - "org_unit_type": row_ou.org_unit_type.as_dict_for_completeness_stats() if row_ou.org_unit_type else {}, - "parent_org_unit": ( - row_ou.parent.as_dict_for_completeness_stats_with_parent() if row_ou.parent else None - ), + "org_unit_type": row_ou.org_unit_type.as_minimal_dict() if row_ou.org_unit_type else {}, + "parent_org_unit": row_ou.parent.as_minimal_dict_with_parent() if row_ou.parent else None, "has_children": has_children(row_ou), } if temp_org_unit["has_geo_json"] == True: diff --git a/iaso/models/forms.py b/iaso/models/forms.py index 42119fc774..2467607a0e 100644 --- a/iaso/models/forms.py +++ b/iaso/models/forms.py @@ -147,7 +147,7 @@ def as_dict(self, additional_fields=None, show_version=True): return res - def as_dict_for_completeness_stats(self): + def as_minimal_dict(self): return { "name": self.name, "id": self.id, diff --git a/iaso/models/org_unit.py b/iaso/models/org_unit.py index add659e67a..7794cd6dbb 100644 --- a/iaso/models/org_unit.py +++ b/iaso/models/org_unit.py @@ -80,7 +80,14 @@ def filter_for_user_and_app_id( if user and user.is_anonymous and app_id is None: return self.none() - queryset = self.all() + queryset = self.prefetch_related( + "projects", + "projects__account", + "projects__feature_flags", + "allow_creating_sub_unit_types", + "reference_forms", + "sub_unit_types", + ) if user and user.is_authenticated: queryset = queryset.filter(projects__account=user.iaso_profile.account) @@ -146,7 +153,7 @@ def as_dict(self, sub_units=True, app_id=None): res["sub_unit_types"] = sub_unit_types return res - def as_dict_for_completeness_stats(self): + def as_minimal_dict(self): return { "name": self.name, "id": self.id, @@ -501,14 +508,14 @@ def as_dict_for_csv(self): "org_unit_type": self.org_unit_type.name, } - def as_dict_for_completeness_stats_with_parent(self): + def as_minimal_dict_with_parent(self): return { "name": self.name, "id": self.id, - "parent": self.parent.as_dict_for_completeness_stats() if self.parent else None, + "parent": self.parent.as_minimal_dict() if self.parent else None, } - def as_dict_for_completeness_stats(self): + def as_minimal_dict(self): return { "name": self.name, "id": self.id,