def submit_run(self, summary_rb_number, run_number, file_name): """ Submit a run to ActiveMQ :param summary_rb_number: RB number of the experiment as read from the summary file :param run_number: Run number as it appears in lastrun.txt :param file_name: File name e.g. GEM1234.nxs """ # Check to see if the last run exists, if not then raise an exception file_path = os.path.join(self.data_dir, CYCLE_FOLDER, file_name) if os.path.isfile(file_path): # Attempt to read an RB number from the Nexus file. This is most # useful for high frequency instruments like ENGINX where reading # from the summary is unreliable. rb_number = read_rb_number_from_nexus_file(file_path) if rb_number is None: rb_number = summary_rb_number EORM_LOG.info("Submitting '%s' with RB number '%s'", file_name, rb_number) message = Message(instrument=self.instrument_name, rb_number=rb_number, run_number=run_number, data=file_path, started_by=0) # Autoreduction service code message.validate('/queue/DataReady') self.client.send('/queue/DataReady', message, priority='9') else: raise FileNotFoundError( "File does not exist '{}'".format(file_path))
def find_reason_to_skip_run(reduction_run, message: Message, instrument) -> Optional[str]: """ Determines whether the processing should be skippped. The run will be skipped if the message validation fails or if the instrument is paused """ if reduction_run.script == "": return "Script text for current instrument is empty" try: message.validate("/queue/DataReady") except RuntimeError as validation_err: return f"Validation error from handler: {str(validation_err)}" if instrument.is_paused: return f"Run {message.run_number} has been skipped because the instrument {instrument.name} is paused" return None
def test_validate_data_ready_valid(self): """ Test: No exception is raised When: Calling validate for data_ready with a valid message """ message = Message(instrument='GEM', run_number=111, rb_number=222, data='file/path', facility="ISIS", started_by=0) try: self.assertIsNone(message.validate('/queue/DataReady')) except RuntimeError: self.fail()
def data_ready(self, message: Message): """ Called when destination queue was data_ready. Updates the reduction run in the database. """ self._logger.info("Data ready for processing run %s on %s", message.run_number, message.instrument) if not validate_rb_number(message.rb_number): # rb_number is invalid so send message to skip queue and early return message.message = f"Found non-integer RB number: {message.rb_number}" self._logger.warning("%s. Skipping %s%s.", message.message, message.instrument, message.run_number) message.rb_number = 0 run_no = str(message.run_number) instrument = self._get_and_activate_db_inst(message.instrument) status = self._utils.status.get_skipped() if instrument.is_paused \ else self._utils.status.get_queued() # This must be done before looking up the run version to make sure # the record exists experiment = db_access.get_experiment(message.rb_number, create=True) run_version = db_access.find_highest_run_version(run_number=run_no, experiment=experiment) run_version += 1 message.run_version = run_version # Get the script text for the current instrument. If the script text # is null then send to # error queue script_text = self._utils. \ instrument_variable.get_current_script_text(instrument.name)[0] if script_text is None: self.reduction_error(message) raise InvalidStateException( "Script text for current instrument is null") # Make the new reduction run with the information collected so far # and add it into the database reduction_run = db_records.create_reduction_run_record( experiment=experiment, instrument=instrument, message=message, run_version=run_version, script_text=script_text, status=status) db_access.save_record(reduction_run) # Create a new data location entry which has a foreign key linking # it to the current # reduction run. The file path itself will point to a datafile # (e.g. "\isis\inst$\NDXWISH\Instrument\data\cycle_17_1\WISH00038774 # .nxs") data_location = self._data_model.DataLocation( file_path=message.data, reduction_run_id=reduction_run.id) db_access.save_record(data_location) # We now need to create all of the variables for the run such that # the script can run # through in the desired way self._logger.info('Creating variables for run') variables = self._utils.instrument_variable.create_variables_for_run( reduction_run) if not variables: self._logger.warning( "No instrument variables found on %s for run %s", instrument.name, message.run_number) self._logger.info('Getting script and arguments') reduction_script, arguments = self._utils.reduction_run. \ get_script_and_arguments(reduction_run) message.reduction_script = reduction_script message.reduction_arguments = arguments # Make sure the RB number is valid try: message.validate("/queue/DataReady") except RuntimeError as validation_err: self._logger.error("Validation error from handler: %s", str(validation_err)) self._client.send_message('/queue/ReductionSkipped', message) return if instrument.is_paused: self._logger.info("Run %s has been skipped", message.run_number) else: self._client.send_message('/queue/ReductionPending', message) self._logger.info("Run %s ready for reduction", message.run_number)