Skip to content

Survey.generate_report() — add job timeout and cancel support #2531

Open

Description

@hildermesmedeiros

Is your feature request related to a problem? Please describe.
Image
In the example above I Had to cancel it manually, after 2h.

Survey.generate_report() submits a Feature Report job and polls forever with no timeout (internal loop sleeps while esriJobExecuting with no deadline). In batch/ETL PDF generation, a stuck job hangs the process indefinitely. The method also does not return jobId, so callers cannot cancel a hung job via the Survey123 cancel endpoint.

We had to bypass generate_report() and reimplement submit + poll against the same REST API just to add a timeout and a real cancel.

from arcgis.gis import GIS
from arcgis.apps.survey123 import SurveyManager

gis = GIS(url, username, password)
survey = SurveyManager(gis).get("<survey_item_id>")
template = gis.content.get("<report_template_item_id>")

# Can hang forever if the job never leaves esriJobExecuting
# (no timeout kwarg; no jobId returned to cancel)
result = survey.generate_report(
    report_template=template,
    where="OBJECTID=1",
    utc_offset="+00:00",
    output_format="pdf",
)

Describe the solution you'd like
Add optional timeout / cancel controls on Survey.generate_report() (or SurveyManager):

  1. job_timeout (seconds) — stop polling after N seconds and raise a clear error (e.g. TimeoutError).
  2. cancel_on_timeout — call POST .../api/featureReport/jobs/{jobId}/cancel so the remote job does not keep running after the client gives up.
  3. Optionally expose jobId (or a job handle) so callers can cancel/track jobs themselves.

Example:

result = survey.generate_report(
    report_template=template,
    where="OBJECTID=1",
    output_format="pdf",
    job_timeout=90,          # NEW
    cancel_on_timeout=True,  # NEW
)

The cancel endpoint already works in practice (POST .../api/featureReport/jobs/{jobId}/cancel → esriJobStatusCancelled).

Describe alternatives you've considered

  1. Reimplement submit + poll ourselves (current workaround) — duplicate _survey.py logic against /createReport/submitJob, /jobs/{id}/status, and /cancel. Works, but fragile if the private API changes.
  2. External process/watchdog timeout — kills the Python process but does not cancel the remote job; wastes credits and leaves orphan jobs.
  3. Thread + interrupt — still no access to jobId, so cancel is impossible.

Additional context

  • Affected API: arcgis.apps.survey123.Survey.generate_report
  • Use case: automated batch PDF Feature Reports in an ETL pipeline (ArcGIS Enterprise / AGOL)
  • Related endpoints already used successfully outside the Python API:
    • POST /api/featureReport/createReport/submitJob
    • GET /api/featureReport/jobs/{jobId}/status
    • POST /api/featureReport/jobs/{jobId}/cancel

Activity

  1. kyroskoh commented on Aug 13, 2026

    @kyroskoh

    Temporary workaround for 2.4.3 users

    This public repo is docs/samples only, so a library source PR cannot land here. Confirmed in arcgis 2.4.3: Survey.generate_report → _check_status polls forever while status is esriJobSubmitted / esriJobExecuting (no deadline, no cancel, no jobId exposed).

    Full usage, limits, unit tests, and removal steps: misc/tools/issue_2531/README.md on branch fix/issue-2531-survey-generate-report-timeout.

    Monkey-patch module: fix_survey_generate_report_timeout_2531.py

    from misc.tools.issue_2531 import apply, cancel_report_job
    
    apply()  # once per process
    
    result = survey.generate_report(
        report_template=template,
        where="OBJECTID=1",
        output_format="pdf",
        job_timeout=90,          # stop polling after N seconds → TimeoutError
        cancel_on_timeout=True,  # POST .../jobs/{jobId}/cancel
    )
    
    print(survey.last_report_job_id)  # track / cancel manually if needed
    # cancel_report_job(survey)

    Or copy the file next to your script:

    import fix_survey_generate_report_timeout_2531 as fix
    fix.apply()

    What it adds

    1. job_timeout — client-side poll deadline; raises TimeoutError with jobId
    2. cancel_on_timeout — best-effort cancel via POST /api/featureReport/jobs/{jobId}/cancel
    3. survey.last_report_job_id + cancel_report_job(...) so callers can cancel/track without reimplementing submit/poll

    Mock unit tests (no live portal calls):

    python -m unittest misc.tools.issue_2531.test_fix_survey_generate_report_timeout_2531 -v

    Removing the patch when Esri ships a fix

    See When Esri releases a fix in the README. Short version:

    1. Upgrade to the arcgis release that includes the #2531 fix (check the release notes).
    2. Stop importing / calling the workaround (apply(), job_timeout / cancel_on_timeout unless upstream added the same names).
    3. In long-running processes that already called apply():
    from misc.tools.issue_2531 import unapply
    unapply()
    1. Smoke-test Feature Report generation, then optionally delete misc/tools/issue_2531/.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions