diff --git a/octue/cloud/deployment/google/answer_pub_sub_question.py b/octue/cloud/deployment/google/answer_pub_sub_question.py index e079586ea..baef62af9 100644 --- a/octue/cloud/deployment/google/answer_pub_sub_question.py +++ b/octue/cloud/deployment/google/answer_pub_sub_question.py @@ -1,6 +1,5 @@ import logging -from octue.cloud.events.counter import EventCounter from octue.cloud.pub_sub.service import Service from octue.cloud.service_id import create_sruid, get_sruid_parts from octue.configuration import load_service_and_app_configuration @@ -37,8 +36,6 @@ def answer_question(question, project_name): originator = get_nested_attribute(question, "attributes.originator") retry_count = get_nested_attribute(question, "attributes.retry_count") - order = EventCounter() - try: runner = Runner.from_configuration( service_configuration=service_configuration, @@ -48,7 +45,7 @@ def answer_question(question, project_name): ) service.run_function = runner.run - service.answer(question, order) + service.answer(question) logger.info("Analysis successfully run and response sent for question %r.", question_uuid) except BaseException as error: # noqa @@ -58,7 +55,6 @@ def answer_question(question, project_name): originator_question_uuid=originator_question_uuid, parent=parent, originator=originator, - order=order, retry_count=retry_count, ) diff --git a/octue/cloud/emulators/_pub_sub.py b/octue/cloud/emulators/_pub_sub.py index e47a09c13..9164393ca 100644 --- a/octue/cloud/emulators/_pub_sub.py +++ b/octue/cloud/emulators/_pub_sub.py @@ -403,7 +403,6 @@ def ask( "originator_question_uuid": originator_question_uuid, "forward_logs": subscribe_to_logs, "save_diagnostics": save_diagnostics, - "order": 0, "parent": self.id, "originator": originator, "sender": self.id, diff --git a/octue/cloud/events/counter.py b/octue/cloud/events/counter.py deleted file mode 100644 index 5edc208a1..000000000 --- a/octue/cloud/events/counter.py +++ /dev/null @@ -1,35 +0,0 @@ -class EventCounter: - """A mutable counter for keeping track of the emission order of events. This is used in the `Service` class instead - of an integer because it is mutable and can be passed to the `Service._emit_event` method and incremented as - events are emitted. - - :return None: - """ - - def __init__(self): - self.count = 0 - - def __iadd__(self, other): - """Increment the counter by an integer. - - :return octue.cloud.events.counter.EventCounter: the event counter with its count updated - """ - if not isinstance(other, int): - raise ValueError(f"Event counters can only be incremented by an integer; received {other!r}.") - - self.count += other - return self - - def __int__(self): - """Get the counter as an integer. - - :return int: the counter as an integer - """ - return int(self.count) - - def __repr__(self): - """Represent the counter as a string. - - :return str: the counter represented as a string. - """ - return f"<{type(self).__name__}(count={self.count})" diff --git a/octue/cloud/events/replayer.py b/octue/cloud/events/replayer.py index cdc90d320..59560e3fc 100644 --- a/octue/cloud/events/replayer.py +++ b/octue/cloud/events/replayer.py @@ -73,7 +73,6 @@ def _extract_event_and_attributes(self, container): :param dict container: the container of the event :return (any, dict): the event and its attributes """ - container["attributes"]["order"] = int(container["attributes"]["order"]) return container["event"], container["attributes"] def _handle_question(self, event, attributes): diff --git a/octue/cloud/events/validation.py b/octue/cloud/events/validation.py index dc5d3e4a5..41df484db 100644 --- a/octue/cloud/events/validation.py +++ b/octue/cloud/events/validation.py @@ -15,7 +15,7 @@ "result", } -SERVICE_COMMUNICATION_SCHEMA_VERSION = "0.14.0" +SERVICE_COMMUNICATION_SCHEMA_VERSION = "0.14.1" SERVICE_COMMUNICATION_SCHEMA_INFO_URL = "https://strands.octue.com/octue/service-communication" SERVICE_COMMUNICATION_SCHEMA = { diff --git a/octue/cloud/pub_sub/bigquery.py b/octue/cloud/pub_sub/bigquery.py index d0756af26..2a713a6e9 100644 --- a/octue/cloud/pub_sub/bigquery.py +++ b/octue/cloud/pub_sub/bigquery.py @@ -17,7 +17,6 @@ "`sender_type`", "`sender_sdk_version`", "`recipient`", - "`order`", "`other_attributes`", ) diff --git a/octue/cloud/pub_sub/events.py b/octue/cloud/pub_sub/events.py index f022f15e4..f9495b9a3 100644 --- a/octue/cloud/pub_sub/events.py +++ b/octue/cloud/pub_sub/events.py @@ -29,11 +29,8 @@ def extract_event_and_attributes_from_pub_sub_message(message): # Cast attributes to a dictionary to avoid defaultdict-like behaviour from Pub/Sub message attributes container. attributes = dict(getattr_or_subscribe(message, "attributes")) - # Deserialise the `order`, `parent_question_uuid`, `forward_logs`, and `retry_count`, fields if they're present + # Deserialise the `parent_question_uuid`, `forward_logs`, and `retry_count`, fields if they're present # (don't assume they are before validation). - if attributes.get("order"): - attributes["order"] = int(attributes["order"]) - if attributes.get("parent_question_uuid") == "null": attributes["parent_question_uuid"] = None diff --git a/octue/cloud/pub_sub/logging.py b/octue/cloud/pub_sub/logging.py index fdd94fe1b..bacfdff84 100644 --- a/octue/cloud/pub_sub/logging.py +++ b/octue/cloud/pub_sub/logging.py @@ -15,7 +15,6 @@ class GoogleCloudPubSubHandler(logging.Handler): :param str parent: the SRUID of the parent that asked the question these log records are related to :param str originator: the SRUID of the service revision that triggered the tree of questions these log records are related to :param str recipient: the SRUID of the service to send these log records to - :param octue.cloud.events.counter.EventCounter order: an event counter keeping track of the order of emitted events :param int retry_count: the retry count of the question (this is zero if it's the first attempt at the question) :param float timeout: timeout in seconds for attempting to publish each log record :return None: @@ -30,7 +29,6 @@ def __init__( parent, originator, recipient, - order, retry_count, timeout=60, *args, @@ -43,7 +41,6 @@ def __init__( self.parent = parent self.originator = originator self.recipient = recipient - self.order = order self.retry_count = retry_count self.timeout = timeout self._emit_event = event_emitter @@ -63,7 +60,6 @@ def emit(self, record): parent=self.parent, originator=self.originator, recipient=self.recipient, - order=self.order, retry_count=self.retry_count, question_uuid=self.question_uuid, parent_question_uuid=self.parent_question_uuid, diff --git a/octue/cloud/pub_sub/service.py b/octue/cloud/pub_sub/service.py index 50fe907fb..edcdcff99 100644 --- a/octue/cloud/pub_sub/service.py +++ b/octue/cloud/pub_sub/service.py @@ -5,7 +5,6 @@ import importlib.metadata import json import logging -import threading import uuid import google.api_core.exceptions @@ -15,7 +14,6 @@ import octue.exceptions from octue.cloud.events import OCTUE_SERVICES_PREFIX -from octue.cloud.events.counter import EventCounter from octue.cloud.events.validation import raise_if_event_is_invalid from octue.cloud.pub_sub import Subscription, Topic from octue.cloud.pub_sub.events import GoogleCloudPubSubEventHandler, extract_event_and_attributes_from_pub_sub_message @@ -37,10 +35,6 @@ logger = logging.getLogger(__name__) -# A lock to ensure only one event can be emitted at a time so that the order is incremented correctly when events are -# being emitted on multiple threads (e.g. via the main thread and a periodic monitor message thread). This avoids 1) -# events overwriting each other in the parent's message handler and 2) events losing their order. -emit_event_lock = threading.Lock() DEFAULT_NAMESPACE = "default" ANSWERS_NAMESPACE = "answers" @@ -205,19 +199,16 @@ def serve(self, timeout=None, delete_topic_and_subscription_on_exit=False, allow return future, subscriber - def answer(self, question, order=None, heartbeat_interval=120, timeout=30): + def answer(self, question, heartbeat_interval=120, timeout=30): """Answer a question from a parent - i.e. run the child's app on the given data and return the output values. Answers conform to the output values and output manifest schemas specified in the child's Twine file. :param dict|google.cloud.pubsub_v1.subscriber.message.Message question: - :param octue.cloud.events.counter.EventCounter|None order: an event counter keeping track of the order of emitted events :param int|float heartbeat_interval: the time interval, in seconds, at which to send heartbeats :param float|None timeout: time in seconds to keep retrying sending of the answer once it has been calculated :raise Exception: if any exception arises during running analysis and sending its results :return None: """ - order = order or EventCounter() - try: ( question, @@ -242,7 +233,6 @@ def answer(self, question, order=None, heartbeat_interval=120, timeout=30): "originator_question_uuid": originator_question_uuid, "parent": parent, "originator": originator, - "order": order, "retry_count": retry_count, } @@ -463,7 +453,6 @@ def send_exception( originator_question_uuid, parent, originator, - order, retry_count, timeout=30, ): @@ -474,7 +463,6 @@ def send_exception( :param str|None originator_question_uuid: the UUID of the question that triggered all ancestor questions of this question :param str parent: the SRUID of the parent that asked the question this event is related to :param str originator: the SRUID of the service revision that triggered all ancestor questions of this question - :param octue.cloud.events.counter.EventCounter order: an event counter keeping track of the order of emitted events :param int retry_count: the retry count of the question (this is zero if it's the first attempt at the question) :param float|None timeout: time in seconds to keep retrying sending of the exception :return None: @@ -495,7 +483,6 @@ def send_exception( parent=parent, originator=originator, recipient=parent, - order=order, retry_count=retry_count, attributes={"sender_type": CHILD_SENDER_TYPE}, timeout=timeout, @@ -510,14 +497,13 @@ def _emit_event( parent, originator, recipient, - order, retry_count, attributes=None, timeout=30, ): - """Emit a JSON-serialised event as a Pub/Sub message to the services topic with optional message attributes, - incrementing the `order` argument by one. This method is thread-safe. Extra attributes can be added to an event - via the `attributes` argument but the following attributes are always included: + """Emit a JSON-serialised event as a Pub/Sub message to the services topic with optional message attributes. + Extra attributes can be added to an event via the `attributes` argument but the following attributes are always + included: - `uuid` (event UUID) - `question_uuid` - `parent_question_uuid` @@ -527,7 +513,6 @@ def _emit_event( - `sender` - `sender_sdk_version` - `recipient` - - `order` - `datetime` - `retry_count` @@ -538,7 +523,6 @@ def _emit_event( :param str parent: the SRUID of the parent that asked the question this event is related to :param str originator: the SRUID of the service revision that triggered all ancestor questions of this question :param str recipient: the SRUID of the service the event is intended for - :param octue.cloud.events.counter.EventCounter order: an event counter keeping track of the order of emitted events :param int retry_count: the retry count of the question (this is zero if it's the first attempt at the question) :param dict|None attributes: key-value pairs to attach to the event - the values must be strings or bytes :param int|float timeout: the timeout for sending the event in seconds @@ -555,31 +539,27 @@ def _emit_event( attributes["sender_sdk_version"] = self._local_sdk_version attributes["recipient"] = recipient attributes["retry_count"] = retry_count - - with emit_event_lock: - attributes["order"] = int(order) - attributes["datetime"] = datetime.datetime.utcnow().isoformat() - converted_attributes = {} - - for key, value in attributes.items(): - if isinstance(value, bool): - value = str(int(value)) - elif isinstance(value, (int, float)): - value = str(value) - elif value is None: - value = json.dumps(value) - - converted_attributes[key] = value - - future = self.publisher.publish( - topic=self.services_topic.path, - data=json.dumps(event, cls=OctueJSONEncoder).encode(), - ordering_key=question_uuid, - retry=retry.Retry(deadline=timeout), - **converted_attributes, - ) - - order += 1 + attributes["datetime"] = datetime.datetime.utcnow().isoformat() + + converted_attributes = {} + + for key, value in attributes.items(): + if isinstance(value, bool): + value = str(int(value)) + elif isinstance(value, (int, float)): + value = str(value) + elif value is None: + value = json.dumps(value) + + converted_attributes[key] = value + + future = self.publisher.publish( + topic=self.services_topic.path, + data=json.dumps(event, cls=OctueJSONEncoder).encode(), + ordering_key=question_uuid, + retry=retry.Retry(deadline=timeout), + **converted_attributes, + ) return future @@ -628,7 +608,6 @@ def _send_question( parent=self.id, originator=originator, recipient=recipient, - order=EventCounter(), retry_count=retry_count, attributes={ "forward_logs": forward_logs, @@ -649,7 +628,6 @@ def _send_delivery_acknowledgment( originator_question_uuid, parent, originator, - order, retry_count, timeout=30, ): @@ -660,7 +638,6 @@ def _send_delivery_acknowledgment( :param str|None originator_question_uuid: the UUID of the question that triggered all ancestor questions of this question :param str parent: the SRUID of the service that asked the question this event is related to :param str originator: the SRUID of the service revision that triggered all ancestor questions of this question - :param octue.cloud.events.counter.EventCounter order: an event counter keeping track of the order of emitted events :param int retry_count: the retry count of the question (this is zero if it's the first attempt at the question) :param float timeout: time in seconds after which to give up sending :return None: @@ -674,7 +651,6 @@ def _send_delivery_acknowledgment( parent=parent, originator=originator, recipient=parent, - order=order, retry_count=retry_count, attributes={"sender_type": CHILD_SENDER_TYPE}, ) @@ -688,7 +664,6 @@ def _send_heartbeat( originator_question_uuid, parent, originator, - order, retry_count, timeout=30, ): @@ -699,7 +674,6 @@ def _send_heartbeat( :param str|None originator_question_uuid: the UUID of the question that triggered all ancestor questions of this question :param str parent: the SRUID of the parent that asked the question this event is related to :param str originator: the SRUID of the service revision that triggered all ancestor questions of this question - :param octue.cloud.events.counter.EventCounter order: an event counter keeping track of the order of emitted events :param int retry_count: the retry count of the question (this is zero if it's the first attempt at the question) :param float timeout: time in seconds after which to give up sending :return None: @@ -712,7 +686,6 @@ def _send_heartbeat( parent=parent, originator=originator, recipient=parent, - order=order, retry_count=retry_count, attributes={"sender_type": CHILD_SENDER_TYPE}, timeout=timeout, @@ -728,7 +701,6 @@ def _send_monitor_message( originator_question_uuid, parent, originator, - order, retry_count, timeout=30, ): @@ -740,7 +712,6 @@ def _send_monitor_message( :param str|None originator_question_uuid: the UUID of the question that triggered all ancestor questions of this question :param str parent: the SRUID of the service that asked the question this event is related to :param str originator: the SRUID of the service revision that triggered all ancestor questions of this question - :param octue.cloud.events.counter.EventCounter order: an event counter keeping track of the order of emitted events :param int retry_count: the retry count of the question (this is zero if it's the first attempt at the question) :param float timeout: time in seconds to retry sending the message :return None: @@ -753,7 +724,6 @@ def _send_monitor_message( parent=parent, originator=originator, recipient=parent, - order=order, retry_count=retry_count, timeout=timeout, attributes={"sender_type": CHILD_SENDER_TYPE}, diff --git a/tests/cloud/events/test_replayer.py b/tests/cloud/events/test_replayer.py index 13741a98c..3d41ad3c0 100644 --- a/tests/cloud/events/test_replayer.py +++ b/tests/cloud/events/test_replayer.py @@ -28,7 +28,6 @@ def test_no_result_event(self): "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "0", "retry_count": 0, "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", diff --git a/tests/cloud/pub_sub/test_bigquery.py b/tests/cloud/pub_sub/test_bigquery.py index 3e18372c5..ce2248244 100644 --- a/tests/cloud/pub_sub/test_bigquery.py +++ b/tests/cloud/pub_sub/test_bigquery.py @@ -59,7 +59,7 @@ def test_without_tail(self): self.assertEqual( mock_client.mock_calls[1].args[0], "SELECT `originator_question_uuid`, `parent_question_uuid`, `question_uuid`, `kind`, `event`, `datetime`, " - "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, `order`, " + "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, " "`other_attributes` FROM `blah`\nWHERE question_uuid=@relevant_question_uuid\n" "ORDER BY `datetime` ASC\n" "LIMIT @limit", @@ -74,7 +74,7 @@ def test_without_kind(self): mock_client.mock_calls[1].args[0], "SELECT * FROM (\n" "SELECT `originator_question_uuid`, `parent_question_uuid`, `question_uuid`, `kind`, `event`, `datetime`, " - "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, `order`, " + "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, " "`other_attributes` FROM `blah`\nWHERE question_uuid=@relevant_question_uuid\n" "ORDER BY `datetime` DESC\n" "LIMIT @limit\n" @@ -90,7 +90,7 @@ def test_with_kind(self): mock_client.mock_calls[1].args[0], "SELECT * FROM (\n" "SELECT `originator_question_uuid`, `parent_question_uuid`, `question_uuid`, `kind`, `event`, `datetime`, " - "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, `order`, " + "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, " "`other_attributes` FROM `blah`\nWHERE question_uuid=@relevant_question_uuid\nAND kind='result'\n" "ORDER BY `datetime` DESC\n" "LIMIT @limit\n" @@ -106,7 +106,7 @@ def test_with_backend_metadata(self): mock_client.mock_calls[1].args[0], "SELECT * FROM (\n" "SELECT `originator_question_uuid`, `parent_question_uuid`, `question_uuid`, `kind`, `event`, `datetime`, " - "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, `order`, " + "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, " "`other_attributes`, `backend`, `backend_metadata` FROM `blah`\n" "WHERE question_uuid=@relevant_question_uuid\n" "ORDER BY `datetime` DESC\n" @@ -122,7 +122,7 @@ def test_with_parent_question_uuid(self): mock_client.mock_calls[1].args[0], "SELECT * FROM (\n" "SELECT `originator_question_uuid`, `parent_question_uuid`, `question_uuid`, `kind`, `event`, `datetime`, " - "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, `order`, " + "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, " "`other_attributes` FROM `blah`\nWHERE parent_question_uuid=@relevant_question_uuid\n" "ORDER BY `datetime` DESC\n" "LIMIT @limit\n" @@ -137,7 +137,7 @@ def test_with_originator_parent_question_uuid(self): mock_client.mock_calls[1].args[0], "SELECT * FROM (\n" "SELECT `originator_question_uuid`, `parent_question_uuid`, `question_uuid`, `kind`, `event`, `datetime`, " - "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, `order`, " + "`uuid`, `originator`, `parent`, `sender`, `sender_type`, `sender_sdk_version`, `recipient`, " "`other_attributes` FROM `blah`\nWHERE originator_question_uuid=@relevant_question_uuid\n" "ORDER BY `datetime` DESC\n" "LIMIT @limit\n" diff --git a/tests/cloud/pub_sub/test_events.py b/tests/cloud/pub_sub/test_events.py index 499df76b4..b47264f50 100644 --- a/tests/cloud/pub_sub/test_events.py +++ b/tests/cloud/pub_sub/test_events.py @@ -90,7 +90,6 @@ def test_handle_events(self): parent=self.parent.id, originator=self.parent.id, recipient=self.parent.id, - order=event["event"]["order"], retry_count=0, ) @@ -145,7 +144,6 @@ def test_no_timeout(self): parent=self.parent.id, originator=self.parent.id, recipient=self.parent.id, - order=event["event"]["order"], retry_count=0, ) @@ -183,7 +181,6 @@ def test_delivery_acknowledgement(self): parent=self.parent.id, originator=self.parent.id, recipient=self.parent.id, - order=event["event"]["order"], retry_count=0, ) @@ -237,7 +234,6 @@ def test_error_not_raised_if_heartbeat_has_been_received_in_maximum_allowed_inte parent=self.parent.id, originator=self.parent.id, recipient=self.parent.id, - order=event["event"]["order"], retry_count=0, ) @@ -305,7 +301,6 @@ def test_pull_available_events(self): MockMessage.from_primitive( mock_event, attributes={ - "order": 0, "question_uuid": self.question_uuid, "parent": self.parent.id, "sender": self.parent.id, diff --git a/tests/cloud/pub_sub/test_logging.py b/tests/cloud/pub_sub/test_logging.py index febeddd57..000d9e42e 100644 --- a/tests/cloud/pub_sub/test_logging.py +++ b/tests/cloud/pub_sub/test_logging.py @@ -5,7 +5,6 @@ from octue.cloud.emulators._pub_sub import MESSAGES, MockService from octue.cloud.emulators.child import ServicePatcher -from octue.cloud.events.counter import EventCounter from octue.cloud.pub_sub.logging import GoogleCloudPubSubHandler from octue.resources.service_backends import GCPPubSubBackend from tests.base import BaseTestCase @@ -49,7 +48,6 @@ def test_emit(self): parent="another/service:1.0.0", originator="another/service:1.0.0", recipient="another/service:1.0.0", - order=EventCounter(), retry_count=0, ).emit(log_record) @@ -84,7 +82,6 @@ def test_emit_with_non_json_serialisable_args(self): parent="another/service:1.0.0", originator="another/service:1.0.0", recipient="another/service:1.0.0", - order=EventCounter(), retry_count=0, ).emit(record) diff --git a/tests/data/events.json b/tests/data/events.json index c403fe6ce..dd3fa62e9 100644 --- a/tests/data/events.json +++ b/tests/data/events.json @@ -6,7 +6,6 @@ "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "0", "retry_count": 0, "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", @@ -48,7 +47,6 @@ "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "1", "retry_count": 0, "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", @@ -90,7 +88,6 @@ "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "2", "retry_count": 0, "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", @@ -132,7 +129,6 @@ "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "3", "retry_count": 0, "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", @@ -174,7 +170,6 @@ "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "4", "retry_count": 0, "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", @@ -216,7 +211,6 @@ "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "5", "retry_count": 0, "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", @@ -253,7 +247,6 @@ "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "6", "retry_count": 0, "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", @@ -273,7 +266,6 @@ "attributes": { "datetime": "2024-04-11T10:46:48.236064", "uuid": "a9de11b1-e88f-43fa-b3a4-40a590c3443f", - "order": "7", "question_uuid": "d45c7e99-d610-413b-8130-dd6eef46dda6", "parent_question_uuid": "5776ad74-52a6-46f7-a526-90421d91b8b2", "originator_question_uuid": "86dc55b2-4282-42bd-92d0-bd4991ae7356",