Skip to content

Commit 971c425

Browse files
fix(app): incorrect values inserted when retrying queue item
In #7688 we optimized queuing preparation logic. This inadvertently broke retrying queue items. Previously, a `NamedTuple` was used to store the values to insert in the DB when enqueuing. This handy class provides an API similar to a dataclass, where you can instantiate it with kwargs in any order. The resultant tuple re-orders the kwargs to match the order in the class definition. For example, consider this `NamedTuple`: ```py class SessionQueueValueToInsert(NamedTuple): foo: str bar: str ``` When instantiating it, no matter the order of the kwargs, if you make a normal tuple out of it, the tuple values are in the same order as in the class definition: ``` t1 = SessionQueueValueToInsert(foo="foo", bar="bar") print(tuple(t1)) # -> ('foo', 'bar') t2 = SessionQueueValueToInsert(bar="bar", foo="foo") print(tuple(t2)) # -> ('foo', 'bar') ``` So, in the old code, when we used the `NamedTuple`, it implicitly normalized the order of the values we insert into the DB. In the retry logic, the values of the tuple were not ordered correctly, but the use of `NamedTuple` had secretly fixed the order for us. In the linked PR, `NamedTuple` was dropped for a normal tuple, after profiling showed `NamedTuple` to be meaningfully slower than a normal tuple. The implicit order normalization behaviour wasn't understood, and the order wasn't fixed when changin the retry logic to use a normal tuple instead of `NamedTuple`. This results in a bug where we incorrectly create queue items in the DB. For example, we stored the `destination` in the `field_values` column. When such an incorrectly-created queue item is dequeued, it fails pydantic validation and causes what appears to be an endless loop of errors. The only user-facing solution is to add this line to `invokeai.yaml` and restart the app: ```yaml clear_queue_on_startup: true ``` On next startup, the queue is forcibly cleared before the error loop is triggered. Then the user should remove this line so their queue is persisted across app launches per usual. The solution is simple - fix the ordering of the tuple. I also added a type annotation and comment to the tuple type alias definition. Note: The endless error loop, as a general problem, will take some thinking to fix. The queue service methods to cancel and fail a queue item still retrieve it and parse it. And the list queue items methods parse the queue items. Bit of a catch 22, maybe the solution is to simply delete totally borked queue items and log an error.
1 parent b09008c commit 971c425

File tree

2 files changed

+12
-8
lines changed

2 files changed

+12
-8
lines changed

invokeai/app/services/session_queue/session_queue_common.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,14 +563,17 @@ def calc_session_count(batch: Batch) -> int:
563563
str, # session (as stringified JSON)
564564
str, # session_id
565565
str, # batch_id
566-
str | None, # field_values (optional, as stringified JSON)
566+
str | None, # field_values (optional, as stringified JSON)
567567
int, # priority
568568
str | None, # workflow (optional, as stringified JSON)
569569
str | None, # origin (optional)
570570
str | None, # destination (optional)
571571
int | None, # retried_from_item_id (optional, this is always None for new items)
572572
]
573-
"""A type alias for the tuple of values to insert into the session queue table."""
573+
"""A type alias for the tuple of values to insert into the session queue table.
574+
575+
**If you change this, be sure to update the `enqueue_batch` and `retry_items_by_id` methods in the session queue service!**
576+
"""
574577

575578

576579
def prepare_values_to_insert(

invokeai/app/services/session_queue/session_queue_sqlite.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
SessionQueueItemDTO,
2828
SessionQueueItemNotFoundError,
2929
SessionQueueStatus,
30+
ValueToInsertTuple,
3031
calc_session_count,
3132
prepare_values_to_insert,
3233
)
@@ -689,7 +690,7 @@ def retry_items_by_id(self, queue_id: str, item_ids: list[int]) -> RetryItemsRes
689690
"""Retries the given queue items"""
690691
try:
691692
cursor = self._conn.cursor()
692-
values_to_insert: list[tuple] = []
693+
values_to_insert: list[ValueToInsertTuple] = []
693694
retried_item_ids: list[int] = []
694695

695696
for item_id in item_ids:
@@ -715,16 +716,16 @@ def retry_items_by_id(self, queue_id: str, item_ids: list[int]) -> RetryItemsRes
715716
else queue_item.item_id
716717
)
717718

718-
value_to_insert = (
719+
value_to_insert: ValueToInsertTuple = (
719720
queue_item.queue_id,
721+
cloned_session_json,
722+
cloned_session.id,
720723
queue_item.batch_id,
721-
queue_item.destination,
722724
field_values_json,
723-
queue_item.origin,
724725
queue_item.priority,
725726
workflow_json,
726-
cloned_session_json,
727-
cloned_session.id,
727+
queue_item.origin,
728+
queue_item.destination,
728729
retried_from_item_id,
729730
)
730731
values_to_insert.append(value_to_insert)

0 commit comments

Comments
 (0)