def _update_last_scalar_events_for_task(self, last_events, event): """ Update last_events structure with the provided event details if this event is more recent than the currently stored event for its metric/variant combination. last_events contains [hashed_metric_name -> hashed_variant_name -> event]. Keys are hashed to avoid mongodb key conflicts due to invalid characters and/or long field names. """ metric = event.get("metric") variant = event.get("variant") if not (metric and variant): return metric_hash = dbutils.hash_field_name(metric) variant_hash = dbutils.hash_field_name(variant) last_event = last_events[metric_hash][variant_hash] event_iter = event.get("iter", 0) event_timestamp = event.get("timestamp", 0) value = event.get("value") if value is not None and ((event_iter, event_timestamp) >= ( last_event.get("iter", event_iter), last_event.get("timestamp", event_timestamp), )): event_data = { k: event[k] for k in ("value", "metric", "variant", "iter", "timestamp") if k in event } event_data["min_value"] = min(value, last_event.get("min_value", value)) event_data["max_value"] = max(value, last_event.get("max_value", value)) last_events[metric_hash][variant_hash] = event_data
def _update_last_scalar_events_for_task(self, last_events, event): """ Update last_events structure with the provided event details if this event is more recent than the currently stored event for its metric/variant combination. last_events contains [hashed_metric_name -> hashed_variant_name -> event]. Keys are hashed to avoid mongodb key conflicts due to invalid characters and/or long field names. """ metric = event.get("metric") variant = event.get("variant") if not (metric and variant): return metric_hash = dbutils.hash_field_name(metric) variant_hash = dbutils.hash_field_name(variant) timestamp = last_events[metric_hash][variant_hash].get("timestamp", None) if timestamp is None or timestamp < event["timestamp"]: last_events[metric_hash][variant_hash] = event
def update_statistics( task_id: str, company_id: str, last_update: datetime = None, last_iteration: int = None, last_iteration_max: int = None, last_scalar_values: Sequence[Tuple[Tuple[str, ...], Any]] = None, last_events: Dict[str, Dict[str, dict]] = None, **extra_updates, ): """ Update task statistics :param task_id: Task's ID. :param company_id: Task's company ID. :param last_update: Last update time. If not provided, defaults to datetime.utcnow(). :param last_iteration: Last reported iteration. Use this to set a value regardless of current task's last iteration value. :param last_iteration_max: Last reported iteration. Use this to conditionally set a value only if the current task's last iteration value is smaller than the provided value. :param last_scalar_values: Last reported metrics summary for scalar events (value, metric, variant). :param last_events: Last reported metrics summary (value, metric, event type). :param extra_updates: Extra task updates to include in this update call. :return: """ last_update = last_update or datetime.utcnow() if last_iteration is not None: extra_updates.update(last_iteration=last_iteration) elif last_iteration_max is not None: extra_updates.update(max__last_iteration=last_iteration_max) if last_scalar_values is not None: def op_path(op, *path): return "__".join((op, "last_metrics") + path) for path, value in last_scalar_values: if path[-1] == "min_value": extra_updates[op_path("min", *path[:-1], "min_value")] = value elif path[-1] == "max_value": extra_updates[op_path("max", *path[:-1], "max_value")] = value else: extra_updates[op_path("set", *path)] = value if last_events is not None: def events_per_type( metric_data: Dict[str, dict]) -> Dict[str, EventStats]: return { event_type: EventStats(last_update=event["timestamp"]) for event_type, event in metric_data.items() } metric_stats = { dbutils.hash_field_name(metric_key): MetricEventStats( metric=metric_key, event_stats_by_type=events_per_type(metric_data)) for metric_key, metric_data in last_events.items() } extra_updates["metric_stats"] = metric_stats Task.objects(id=task_id, company=company_id).update(upsert=False, last_update=last_update, **extra_updates)