Visitar URL original
feat: add opt-in recovery for AIPrompt results by ranadeepsingh · Pull Request #2813 · microsoft/SynapseML · GitHub
Skip to content

feat: add opt-in recovery for AIPrompt results - #2813

Open
Rana Singh (ranadeepsingh) wants to merge 7 commits into
microsoft:masterfrom
ranadeepsingh:feat/aiprompt-recovery-20261105
Open

Rana Singh (ranadeepsingh) wants to merge 7 commits into
microsoft:masterfrom
ranadeepsingh:feat/aiprompt-recovery-20261105

Conversation

@ranadeepsingh

@ranadeepsingh Rana Singh (ranadeepsingh) commented Nov 5, 2026 •

Copy link
Copy Markdown
Collaborator

An interrupted AI inference job can leave users repeating expensive model calls. This PR lets AIPrompt save its inputs and completed results in Delta, so users can reopen saved results or continue unfinished work instead of restarting the whole job.

This is optional saved progress and recovery, not a new model API or a guarantee of exactly-once billing.

Related Issues/PRs

The other prerequisite fixes (#2818, #2819 and #2820) are already merged and integrated. This PR does not close the broader umbrella or the separate live Decisions qualification in #2760.

What changes are proposed in this pull request?

For jobs such as classifying support tickets or extracting information from documents:

  1. Save progress: setting outputPath snapshots the input and saves row results/errors in bounded Delta batches.
  2. Read without calling the model again: loadOutput returns saved outcomes; getOutputStatus reports progress.
  3. Continue after interruption: resume uses the saved input and processes only rows whose outcome has not yet been saved. Saved row errors are final outcomes, not automatically retried.

Example: assume prompt is a configured AIPrompt, tickets is the input DataFrame, and spark has Delta support.

from synapse.ml.services.ai import AIPrompt

path = "Files/aiprompt/ticket-run-001"  # Use a fresh path for each new job.
durable = prompt.copy({}).setOutputPath(path).setOutputBatchSize(1000)
results = durable.transform(tickets)  # Runs inference and saves results immediately.
results.show()                       # Reads saved results; no new model calls.

saved = AIPrompt.loadOutput(spark, path)
status = AIPrompt.getOutputStatus(spark, path)

After an interruption, recreate the matching stage/configuration and output path, supply credentials, and call durable.resume(spark). No input DataFrame is needed: recovery uses the stored snapshot. Stop the previous Spark application's work first. If it left ownership recorded, follow the explicit owner-release procedure in the recovery guide before resuming.

Important boundaries:

  • Without outputPath, ordinary lazy inference is unchanged and does not require Delta.
  • Durable execution is a standalone, one-run job, not a reusable stage inside a Spark ML pipeline. A new job needs a new path.
  • Resume requires matching configuration, SynapseML build and Spark identity. This is not a cross-version migration feature.
  • Requests whose outcomes were not saved can run again and incur another charge.
  • Saving progress adds storage work. Initial execution was 18.5-22.4x slower in the prior fast synthetic benchmark; this is not a live-model performance measurement.

How is this patch tested?

Validated predecessor ae322b24ae: 60 focused Scala tests and two installed-wheel Python tests passed, with zero failures, skips or cancellations. All-module production/test compilation and Scala style, core/cognitive packaging, and Black also passed. Current head 72fd2ebeaf integrates the latest master; all seven patch commits are unchanged by git range-diff, and the core, cognitive, build, dependency and pipeline trees are identical. Fresh targeted/package validation and Azure CI are in progress; the completed runs below are not relabeled as current-head executions.

The Scala runs include three cache/preflight cases, 52 endpoint/API-version/recovery/input cases, and five independent-driver process cases with real Delta explicitly required. These verify committed-batch and lost-acknowledgement recovery without replay, permitted replay of paid responses lost before commit, interruption while waiting for the control lock, driver death at each initialization write, and a single inferencing winner during concurrent first creation/later acquisition.

The Python tests use newly packaged JARs and installed wheels with real Delta, verifying recovery without replaying committed rows and explicit confirmation before administrative owner release. The harness verified all 451 packaged Python files against generated sources, JVM class origins and artifact hashes. Its recorded head is ae322b24aef1a5f6d4a6cf22f6abe1c53e0b3257, with an empty source diff.

Predecessor Azure build 246489507 succeeded, including all 66 jobs and Databricks GPU E2E. It is a pullRequest build of refs/pull/2813/merge with source head ae322b24ae, not a manual branch-only build. The review of that head has no active or suppressed findings; its request for maintainer review of ownership, ambiguous commits and paid-request replay still applies. Separate five-API usability validation and the shared parser fix are in #2834.

Remaining readiness boundary: recurring Delta/process recovery coverage and maintainer durability/replay review remain required. The predecessor ordinary Azure AI job reports 522 passed and 188 canceled; its green status is not evidence that the optional Delta/process scenarios executed. The focused local results above explicitly enabled those dependencies and all five requested process scenarios and had zero cancellations, but do not replace recurring coverage for the full recovery suite. Broader Fabric qualification is prior-head evidence. A new Fabric smoke attempt failed with HTTP 500 while creating its scratch lakehouse, before Spark started; it provides no runtime coverage. See the prior assessment.

Exact local validation commands and results

Commands used JDK 11, Spark 3.5.0 and Scala 2.12.17. Delta was supplied only through set cognitive / libraryDependencies += "io.delta" %% "delta-spark" % "3.2.0" % Test, with core/cognitive test forking disabled, SYNAPSEML_REQUIRE_DELTA_TESTS=true and AIPROMPT_RUN_PROCESS_TESTS=true. Every result below belongs to ae322b24ae.

Command Result
sbt compile Test/compile scalastyle Test/scalastyle Passed at ae322b24ae, all modules.
sbt 'cognitive/testOnly *AIPromptRecoveryPreflightSuite *AIPromptDurableBindingsSuite -- -z cache' 3 passed, zero skipped/canceled.
sbt 'cognitive/testOnly *AIPromptRecoveryEndpointSuite *AIPromptApiVersionSuite *AIPromptRecoverySuite *AIPromptInputSuite' 52 passed, zero skipped/canceled.
sbt 'cognitive/testOnly *AIPromptStorageProcessSuite -- -z "killed driver recovery" -z "driver death after paid responses"' 2 passed with real independent drivers and Delta, zero skipped/canceled.
sbt 'cognitive/testOnly *AIPromptStorageProcessSuite -- -z "administrative release can cancel" -z "driver death at every initialization" -z "separate drivers racing"' 3 passed with real independent drivers and Delta, zero skipped/canceled.
sbt core/packageBin cognitive/packageBin cognitive/Test/packageBin core/packagePython cognitive/packagePython Passed.
python -m black --check --extend-exclude 'docs/' . with Black 22.3.0 Passed; 223 files unchanged.
python "$evidence/run_api_matrix.py" --recovery 2 passed, zero failures/errors/skips. Session-local installed-wheel/provenance harness; $evidence is the retained evidence directory.
git diff --check Passed.
  • I have written tests (not required for typo or doc fix) and confirmed the proposed feature/bug-fix/change works.

Does this PR change any dependencies?

  • No. You can skip this section.
  • Yes. Make sure the dependencies are resolved correctly, and list changes here.

No dependency manifests or pins change. Only users enabling durable execution need to supply a compatible Delta runtime.

Does this PR add a new feature? If so, have you added samples on website?

  • No. You can skip this section.
  • Yes. Make sure you have added samples following below steps.

Added Durable AI results.md and Quickstart - Durable AI results.ipynb. Notebook execution is disabled by default; the recovery notebook itself has not been executed as a qualification test.

  1. Find the corresponding markdown file for your new feature in website/docs/documentation folder.
    Make sure you choose the correct class estimators/transformers and namespace.
  2. Follow the pattern in markdown file and add another section for your new API, including pyspark, scala (and .NET potentially) samples.
  3. Make sure the DocTable points to correct API link.
  4. Navigate to website folder, and run npm start to make sure the website renders correctly.
  5. Don't forget to add <!--pytest-codeblocks:cont--> before each python code blocks to enable auto-tests for python samples.
  6. Make sure the WebsiteSamplesTests job pass in the pipeline.

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants