Add export_history task

Which prepares the export model store.
This commit is contained in:
mvdbeek
2021-04-14 17:42:07 +02:00
parent e557f3eb60
commit 64b6f7fa95
11 changed files with 83 additions and 43 deletions
@@ -9,7 +9,7 @@ import { STATES } from "./states";
// Job-state-summary lists
const NON_TERMINAL_STATES = [STATES.NEW, STATES.QUEUED, STATES.RUNNING];
const NON_TERMINAL_STATES = [STATES.NEW, STATES.WAITING, STATES.QUEUED, STATES.RUNNING];
const ERROR_STATES = [
STATES.ERROR,
@@ -11,6 +11,8 @@ export const STATES = {
SETTING_METADATA: "setting_metadata",
/** was created without a tool */
NEW: "new",
/** job is being created, but not put into job queue yet */
WAITING: "waiting",
/** has no data */
EMPTY: "empty",
/** has successfully completed running */
+1 -1
View File
@@ -4,7 +4,7 @@ import AJAX_QUEUE from "utils/ajax-queue";
/** ms between fetches when checking running jobs/datasets for updates */
var UPDATE_DELAY = 2000;
var NON_TERMINAL_STATES = ["new", "queued", "running"];
var NON_TERMINAL_STATES = ["new", "queued", "running", "waiting"];
var ERROR_STATES = ["error", "deleted"];
var TERMINAL_STATES = ["ok"].concat(ERROR_STATES);
/** Fetch state on add or just wait for polling to start. */
+8 -10
View File
@@ -153,6 +153,12 @@ class GalaxyManagerApplication(MinimalManagerApp, MinimalGalaxyApplication):
self._register_singleton(MinimalManagerApp, self)
self.execution_timer_factory = self._register_singleton(ExecutionTimerFactory, ExecutionTimerFactory(self.config))
self.configure_fluent_log()
self.application_stack = self._register_singleton(ApplicationStack, application_stack_instance(app=self))
# Initialize job metrics manager, needs to be in place before
# config so per-destination modifications can be made.
self.job_metrics = self._register_singleton(JobMetrics, JobMetrics(self.config.job_metrics_config_file, app=self))
# Initialize the job management configuration
self.job_config = self._register_singleton(jobs.JobConfiguration)
# Tag handler
self.tag_handler = self._register_singleton(GalaxyTagHandler)
@@ -167,6 +173,8 @@ class GalaxyManagerApplication(MinimalManagerApp, MinimalGalaxyApplication):
self.library_folder_manager = self._register_singleton(FolderManager)
self.library_manager = self._register_singleton(LibraryManager)
self.role_manager = self._register_singleton(RoleManager)
from galaxy.jobs.manager import JobManager
self.job_manager = self._register_singleton(JobManager)
# ConfiguredFileSources
self.file_sources = self._register_singleton(ConfiguredFileSources, ConfiguredFileSources.from_app_config(self.config))
@@ -209,7 +217,6 @@ class UniverseApplication(StructuredApp, GalaxyManagerApplication):
]
self._register_singleton(StructuredApp, self)
# A lot of postfork initialization depends on the server name, ensure it is set immediately after forking before other postfork functions
self.application_stack = self._register_singleton(ApplicationStack, application_stack_instance(app=self))
self.application_stack.register_postfork_function(self.application_stack.set_postfork_server_name, self)
self.config.reload_sanitize_allowlist(explicit='sanitize_allowlist_file' in kwargs)
self.amqp_internal_connection_obj = galaxy.queues.connection_from_config(self.config)
@@ -234,16 +241,9 @@ class UniverseApplication(StructuredApp, GalaxyManagerApplication):
# Data providers registry.
self.data_provider_registry = self._register_singleton(DataProviderRegistry)
# Initialize job metrics manager, needs to be in place before
# config so per-destination modifications can be made.
self.job_metrics = self._register_singleton(JobMetrics, JobMetrics(self.config.job_metrics_config_file, app=self))
# Initialize error report plugins.
self.error_reports = self._register_singleton(ErrorReports, ErrorReports(self.config.error_report_file, app=self))
# Initialize the job management configuration
self.job_config = self._register_singleton(jobs.JobConfiguration)
# Setup a Tool Cache
self.tool_cache = self._register_singleton(ToolCache)
self.tool_shed_repository_cache = self._register_singleton(ToolShedRepositoryCache)
@@ -305,8 +305,6 @@ class UniverseApplication(StructuredApp, GalaxyManagerApplication):
self.config.oidc_config_file,
self.config.oidc_backends_config_file)
# Start the job manager
from galaxy.jobs import manager
self.job_manager = self._register_singleton(manager.JobManager)
self.application_stack.register_postfork_function(self.job_manager.start)
self.proxy_manager = ProxyManager(self.config)
+26 -2
View File
@@ -3,17 +3,21 @@ from sqlalchemy.orm.scoping import (
scoped_session,
)
from galaxy import model
from galaxy.app import MinimalManagerApp
from galaxy.celery import celery_app
from galaxy.jobs.manager import JobManager
from galaxy.managers.hdas import HDAManager
from galaxy.managers.lddas import LDDAManager
from galaxy.model import User
from galaxy.util.custom_logging import get_logger
from . import get_galaxy_app
log = get_logger(__name__)
CELERY_TASKS = []
def galaxy_task(func):
CELERY_TASKS.append(func.__name__)
app = get_galaxy_app()
if app:
return magic_bind_to_container(app)(func)
@@ -24,7 +28,7 @@ def galaxy_task(func):
@galaxy_task
def recalculate_user_disk_usage(session: scoped_session, user_id=None):
if user_id:
user = session.query(User).get(user_id)
user = session.query(model.User).get(user_id)
if user:
user.calculate_and_set_disk_usage()
log.info(f"New user disk usage is {user.disk_usage}")
@@ -49,3 +53,23 @@ def set_metadata(hda_manager: HDAManager, ldda_manager: LDDAManager, dataset_id,
elif model_class == 'LibraryDatasetDatasetAssociation':
dataset = ldda_manager.by_id(dataset_id)
dataset.datatype.set_meta(dataset)
@celery_app.task(ignore_result=True)
@galaxy_task
def export_history(
app: MinimalManagerApp,
sa_session: scoped_session,
job_manager: JobManager,
store_directory,
history_id,
job_id,
include_hidden=False,
include_deleted=False):
history = sa_session.query(model.History).get(history_id)
with model.store.DirectoryModelExportStore(store_directory, app=app, export_files="symlink") as export_store:
export_store.export_history(history, include_hidden=include_hidden, include_deleted=include_deleted)
job = sa_session.query(model.Job).get(job_id)
job.state = model.Job.states.NEW
sa_session.flush()
job_manager.enqueue(job)
+12 -10
View File
@@ -109,7 +109,6 @@ class ExportHistoryToolAction(ToolAction):
if trans.user:
# If this is an actual user, run the job as that individual. Otherwise we're running as guest.
job.user_id = trans.user.id
start_job_state = job.state # should be job.states.NEW
job.state = job.states.WAITING # we need to set job state to something other than NEW, or else when tracking jobs in db it will be picked up before we have added input / output parameters
trans.sa_session.add(job)
@@ -135,10 +134,10 @@ class ExportHistoryToolAction(ToolAction):
#
# Setup job and job wrapper.
#
job_wrapper = JobExportHistoryArchiveWrapper(trans.app, job)
cmd_line = job_wrapper.setup_job(history, store_directory, include_hidden=incoming['include_hidden'],
include_deleted=incoming['include_deleted'],
compressed=compressed)
cmd_line = f"--galaxy-version '{job.galaxy_version}'"
if compressed:
cmd_line += " -G"
cmd_line = f"{cmd_line} {store_directory}"
#
# Add parameters to job_parameter table.
@@ -165,11 +164,14 @@ class ExportHistoryToolAction(ToolAction):
for name, value in tool.params_to_strings(incoming, trans.app).items():
job.add_parameter(name, value)
trans.sa_session.flush()
job.state = start_job_state # job inputs have been configured, restore initial job state
# Queue the job for execution
trans.app.job_manager.enqueue(job, tool=tool)
trans.log_event("Added export history job to the job queue, id: %s" % str(job.id), tool_id=job.tool_id)
job_wrapper = JobExportHistoryArchiveWrapper(trans.app, job.id)
job_wrapper.setup_job(
history,
store_directory,
include_hidden=incoming['include_hidden'],
include_deleted=incoming['include_deleted'],
compressed=compressed)
return job, {}
+8 -18
View File
@@ -6,7 +6,6 @@ import shutil
from galaxy import model
from galaxy.model import store
from galaxy.util.path import external_chown
from galaxy.version import VERSION_MAJOR
log = logging.getLogger(__name__)
@@ -93,23 +92,14 @@ class JobExportHistoryArchiveWrapper:
self.sa_session = self.app.model.context
def setup_job(self, history, store_directory, include_hidden=False, include_deleted=False, compressed=True):
"""Perform setup for job to export a history into an archive.
Method generates attribute files for export, sets the corresponding attributes
in the jeha object, and returns a command line for running the job. The command
line includes the command, inputs, and options; it does not include the output
file because it must be set at runtime.
"""
Perform setup for job to export a history into an archive.
"""
app = self.app
# symlink files on export, on worker files will tarred up in a dereferenced manner.
with store.DirectoryModelExportStore(store_directory, app=app, export_files="symlink") as export_store:
export_store.export_history(history, include_hidden=include_hidden, include_deleted=include_deleted)
#
# Create and return command line for running tool.
#
options = f"--galaxy-version '{VERSION_MAJOR}'"
if compressed:
options += " -G"
return f"{options} {store_directory}"
from galaxy.celery.tasks import export_history
if app.config.enable_celery_tasks:
# symlink files on export, on worker files will tarred up in a dereferenced manner.
export_history.delay(store_directory=store_directory, history_id=history.id, job_id=self.job_id, include_hidden=include_hidden, include_deleted=include_deleted)
else:
export_history(store_directory=store_directory, history_id=history.id, job_id=self.job_id, include_hidden=include_hidden, include_deleted=include_deleted)
+14
View File
@@ -0,0 +1,14 @@
from functools import wraps
def rebind_container_to_task(app):
from galaxy.celery import tasks
def magic_bind_dynamic(func):
return wraps(func)(app.magic_partial(func, shared=None))
for task in tasks.CELERY_TASKS:
task_fn = getattr(tasks, task)
task_fn = getattr(task_fn, '__wrapped__', task_fn)
container_bound_task = magic_bind_dynamic(task_fn)
setattr(tasks, task, container_bound_task)
+3
View File
@@ -34,6 +34,7 @@ from galaxy.util import asbool, download_to_file, galaxy_directory
from galaxy.util.properties import load_app_properties
from galaxy.webapps.galaxy import buildapp
from galaxy_test.base.api_util import get_admin_api_key, get_user_api_key
from galaxy_test.base.celery_helper import rebind_container_to_task
from galaxy_test.base.env import (
DEFAULT_WEB_HOST,
target_url_parts,
@@ -626,6 +627,8 @@ def build_galaxy_app(simple_kwargs):
)
# Build the Universe Application
app = GalaxyUniverseApplication(**simple_kwargs)
rebind_container_to_task(app)
log.info("Embedded Galaxy application started")
global galaxy_context
+2
View File
@@ -622,6 +622,8 @@ def _import_export(app, h, dest_export=None):
dest_export = os.path.join(dest_parent, "moo.tgz")
job = model.Job()
app.model.session.add(job, h)
app.model.session.flush()
jeha = model.JobExportHistoryArchive.create_for_history(
h, job, app.model.context, app.object_store, compressed=True
)
+6 -1
View File
@@ -27,6 +27,7 @@ from galaxy.util import StructuredExecutionTimer
from galaxy.util.bunch import Bunch
from galaxy.util.dbkeys import GenomeBuilds
from galaxy.web_stack import ApplicationStack
from galaxy_test.base.celery_helper import rebind_container_to_task
# =============================================================================
@@ -86,7 +87,9 @@ class MockApp(di.Container):
self.init_datatypes()
self.job_config = Bunch(
dynamic_params=None,
destinations={}
destinations={},
use_messaging=False,
assign_handler=lambda *args, **kwargs: None
)
self.tool_data_tables = {}
self.dataset_collections_service = None
@@ -99,6 +102,8 @@ class MockApp(di.Container):
self.auth_manager = AuthManager(self.config)
self.user_manager = UserManager(self)
self.execution_timer_factory = Bunch(get_timer=StructuredExecutionTimer)
self.is_job_handler = False
rebind_container_to_task(self)
def url_for(*args, **kwds):
return "/mock/url"