Data Engineering ยท Azure ยท Technical Deep Dive

Technical Deep Dive: Bee Haven Azure Pipeline

The identity saga in full, the Aug 12 rebuild, and the two notebook bugs it fixed along the way

Goal: get the ADF โ†’ Synapse bronze/silver/gold pipeline running end-to-end when triggered by the pipeline itself, not just when run manually โ€” and correct a structural folder-layout mistake from the earlier build.

Result: โœ… Both resolved. Root-caused a two-identity RBAC gap on Aug 11, then rebuilt the pipeline from scratch in a new container on Aug 12 to fix the structural issue and complete the Silver โ†’ Gold layer.

Aug 11 โ€” the identity saga, root-caused

The recurring symptom for the better part of two weeks: a notebook triggered manually in Synapse Studio worked fine. The exact same notebook, triggered by an ADF pipeline, failed every time with AuthorizationPermissionMismatch.

IdentityUsed forRequired roleWhere to grant it
Your own user accountManual testing in Synapse StudioOwner (usually already true)No action needed โ€” this is why manual runs "just work"
Synapse Workspace Managed IdentityLetting Data Factory open a Spark session / read the workspaceSynapse ContributorSynapse Studio โ†’ Manage โ†’ Access control
Data Factory's own Managed IdentityActual notebook code execution when triggered by ADFStorage Blob Data ContributorStorage account โ†’ IAM โ†’ Add role assignment โ†’ search by the ADF resource's name under "Managed identity," not "User"

The Data Factory identity specifically had never been granted the storage role directly โ€” granting it to the Synapse workspace's identity did nothing for Data Factory's own identity, since they're separate principals with separate permission sets. This diagnosis came from a colleague, Andreas, whose notes identified the exact pattern after reviewing the project โ€” including flagging the "Spark job stuck in Queued" quota symptom that came up again the same day, resolved by clearing the blocking session.

Confirmed fixed under the actual ADF-triggered execution context, not just manual Synapse Studio runs โ€” bronze_to_silver_synapse succeeded end-to-end, 6m10s total, with weather integration (Bright Sky API, 29 monthly chunks covering the full 2017โ€“2019 range) folded into the same notebook run for the first time.

Aug 12 โ€” the rebuild

A structural mistake surfaced: the original folder diagram had been "just an idea, not final," and the actual intended structure differed in two ways from what had been built:

Rebuilt from scratch in a new container (lakecontainer1) rather than patching the existing structure in place, to avoid half-migrated state. New ADF pipelines: LC1_copy_to_bronze_new (raw copy) and LC1_bronze_to_processing (Get Metadata โ†’ ForEach โ†’ copy to staging, archive with timestamp, delete from bronze/new) โ€” the same pattern as the original move pipeline, retargeted to the corrected layout.

Notebook bug โ€” an archiving cell that would have silently emptied staging

The old in-notebook archiving cell used mssparkutils.fs.mv directly on DATA_DIR. Once DATA_DIR was repointed to silver/processing (the new pre-cleaning landing zone that ADF also writes to and reads from), that same move call would have silently emptied silver/processing after every run โ€” a real bug that hadn't yet bitten because archiving used to happen elsewhere. Fixed by removing the cell entirely: archiving is now ADF's job (LC1_bronze_to_processing), not the notebook's.

New notebook: LC1_synapse_silver_gold

Loads silver/flow/flow.parquet and silver/weather/weather.json, pivots flow into flow_arrival/flow_departure columns, joins with weather, saves to gold/flow_weather.parquet.

Deliberate precision tradeoff, documented not ignored: weather data is hourly, flow data is per-minute. Flow timestamps are floored to the nearest hour before joining, so multiple flow readings within the same hour share one weather snapshot rather than each having precisely-matched conditions. Per the lesson's explicit guidance, exam-prep priority over analytical precision here.

Two bugs hit and fixed while building the Gold join

1. JSON read failure โ€” spark.read.json() defaults to expecting JSON Lines (one object per line), but the Silver weather file was saved as a pretty-printed JSON array (pandas.to_json(indent=2)). Fixed by reading with .option("multiLine", "true").

2. Merge failure on mismatched timestamp types โ€” one side of the join was timezone-naive (datetime64[us]), the other timezone-aware (datetime64[ns, UTC]). Fixed by forcing both sides to pd.to_datetime(..., utc=True) before flooring to the hour.

Recurring infrastructure friction, not new: hit the 12-vCore quota "Queued"/instant-fail pattern multiple times โ€” a previous session lingering and blocking new ones. Resolved each time via Monitor โ†’ stop the blocking session; once needed the more aggressive Manage โ†’ Apache Spark pools โ†’ Pause settings โ†’ "Force new settings" fix when a normal stop wasn't enough.

โœ… Saved gold table โ†’ abfss://lakecontainer1@lake00bee.dfs.core.windows.net/gold/flow_weather.parquet

Final result

Full chain proven working end-to-end via the actual ADF pipeline at least once: LC1_copy_to_bronze_new โ†’ LC1_bronze_to_processing โ†’ bronze_to_silver_synapse, plus the new Gold notebook run manually to completion.

Left for the next session (and where the trigger bug entered)

Full story: project overview. Compare against the open-source parallel build.