Sobes.tech
Middle

```python import asyncio from typing import List, Optional class Chunk: def __init__(self, items: List[dict]): self.items = items @property def size(self) -> int: return len(self.items) class Producer: async def next(self) -> Optional[Chunk]: # возвращает пачку данных или None ... async def commit(self, chunks: List[Chunk]) -> None: # фиксируем успешную обработку chunks ... class Consumer: max_batch_size = 100 async def consume(self, chunks: List[Chunk]) -> None: total_size = sum(chunk.size for chunk in chunks) if total_size > self.max_batch_size: raise ValueError("batch is too large") # обработка данных ... producer = Producer() consumer = Consumer() async def process(): while True: chunk = await producer.next() if chunk is None: break try: await consumer.consume([chunk]) await producer.commit([chunk]) except Exception as e: print("error but continue:", e) continue if __name__ == "__main__": asyncio.run(process()) ``` This code defines asynchronous producer-consumer classes with batch processing and error handling. The task is to implement or complete the logic for producing, consuming, and committing chunks of data, ensuring batch size limits are respected and errors are handled gracefully.

sobes.tech AI

Answer from AI

In the provided code, you need to implement the methods Producer.next(), Producer.commit(), and the processing logic in Consumer.consume().

  • Producer.next() should asynchronously return the next Chunk object with data or None if there are no more data.
  • Consumer.consume() checks that the total batch size does not exceed max_batch_size and processes the data (e.g., saves or analyzes it).
  • Producer.commit() confirms the successful processing of the batch, for example, by updating the status in a database.

An example implementation with data simulation:

import asyncio
from typing import List, Optional

class Chunk:
    def __init__(self, items: List[dict]):
        self.items = items

    @property
    def size(self) -> int:
        return len(self.items)

class Producer:
    def __init__(self):
        self.data = [
            [{'id': i} for i in range(30)],
            [{'id': i} for i in range(50)],
            [{'id': i} for i in range(120)],  # too large chunk
            [{'id': i} for i in range(20)],
        ]
        self.index = 0

    async def next(self) -> Optional[Chunk]:
        await asyncio.sleep(0.1)  # simulate delay
        if self.index >= len(self.data):
            return None
        chunk = Chunk(self.data[self.index])
        self.index += 1
        return chunk

    async def commit(self, chunks: List[Chunk]) -> None:
        await asyncio.sleep(0.05)  # simulate commit
        print(f"Committed {sum(chunk.size for chunk in chunks)} items")

class Consumer:
    max_batch_size = 100

    async def consume(self, chunks: List[Chunk]) -> None:
        total_size = sum(chunk.size for chunk in chunks)
        if total_size > self.max_batch_size:
            raise ValueError(f"batch is too large: {total_size} > {self.max_batch_size}")
        await asyncio.sleep(0.1)  # simulate processing
        print(f"Consumed {total_size} items")

producer = Producer()
consumer = Consumer()

async def process():
    while True:
        chunk = await producer.next()
        if chunk is None:
            break
        try:
            await consumer.consume([chunk])
            await producer.commit([chunk])
        except Exception as e:
            print("error but continue:", e)
            continue

if __name__ == "__main__":
    asyncio.run(process())

In this example, the third chunk exceeds the limit, causing an exception, which is handled to allow continuation with subsequent chunks.