# Architecture of the TiledWriter Callback To ingest Bluesky data into Tiled, `TiledWriter` callback is subscribed to the Bluesky Run Engine. Structurally, `TiledWriter` consists of two main parts: `RunNormalizer` and `_RunWriter`. The former is responsible for converting legacy document schemas to their latest version; this ensures that existing Bluesky code that relies on older versions of the Bluesky Event Model can still function correctly with `TiledWriter`. For example, while `TiledWriter` natively supports the modern `StreamResource` and `StreamDatum` documents (commonly used in asynchronous plans), the `Resource` and `Datum` documents are automatically converted to their modern counterparts prior to being written to the Tiled catalog. The schema normalization is mostly done by renaming and restructuring certain document fields, but subclassing `RunNormalizer` also allows the user to invoke use-case-specific patches for each type of document and achieve high flexibility. The simplified flowchart of the `RunNormalizer` logic is shown below. It illustrates how the input documents (top) are processed and emitted as output documents (bottom) after specific transformations or caching operations. ```{mermaid} flowchart TD %% Input documents subgraph Input [ ] style Input fill:#ffffff,stroke-width:0 StartIn["Start"] DescriptorIn["Descriptor"] ResourceIn["Resource"] DatumIn["Datum"] EventIn["Event"] StopIn["Stop"] end %% Emitted documents subgraph Output [ ] style Output fill:#ffffff,stroke-width:0 StartOut["Start"] DescriptorOut["Descriptor"] EventOut["Event"] StreamResourceOut["StreamResource"] StreamDatumOut["StreamDatum"] StopOut["Stop"] end %% Processing steps StartIn --> P1["start():
patch → emit"] P1 --> StartOut DescriptorIn --> P2["descriptor():
patch → rename fields →
track internal/external keys → emit"] P2 --> DescriptorOut ResourceIn --> P3["resource():
patch → convert to StreamResource → cache"] P3 --> SResCache[(SRes Cache)] DatumIn --> P4["datum():
patch → cache"] P4 --> DatumCache[(Datum Cache)] EventIn --> P5["event():
patch → split internal/external keys → emit"] P5 -->|internal data| EventOut P5 -->|external data| P6["convert_datum_to_stream_datum()
move datum_kwargs to parameters on SRes"] P6 --> StreamDatumOut P6 --> |only before first SDatum| StreamResourceOut StopIn --> P7["stop():
patch → flush cached StreamDatum"] P7 --> StopOut P7 --> StreamDatumOut P7 --> |if not emitted
already| StreamResourceOut %% Extra connections SResCache --> P6 DatumCache --> P6 %% Styling classDef doc fill:#e0f7fa,stroke:#00796b,stroke-width:1px; classDef emit fill:#f1f8e9,stroke:#33691e,stroke-width:1px; classDef proc fill:#fff3e0,stroke:#e65100,stroke-width:1px; class StartIn,DescriptorIn,ResourceIn,DatumIn,EventIn,StopIn doc; class StartOut,DescriptorOut,EventOut,StreamResourceOut,StreamDatumOut,StopOut emit; class P1,P2,P3,P4,P5,P6,P7 proc; ``` The second component, `_RunWriter`, is the callback that directly communicates with the Tiled server. It uses the `RunRouter` to manage the routing of documents from multiple runs, ensuring that each Bluesky run is handled separately. Furthermore, `TiledWriter` implements a backup mechanism that allows saving the documents to a local file system in case the Tiled server is not available or any other error occurs during the writing process. This ensures that no data is lost and the writing can be retried later.