Skip to content

Promise and Job Queue API Completion#751

Open
buke wants to merge 6 commits into
mainfrom
feat/promise-pr4-job-queue
Open

Promise and Job Queue API Completion#751
buke wants to merge 6 commits into
mainfrom
feat/promise-pr4-job-queue

Conversation

@buke
Copy link
Copy Markdown
Owner

@buke buke commented May 23, 2026

promise and job-queue surface with a consistent Go-facing API aligned to quickjs-ng behavior.

It adds practical runtime control for pending job processing and native callable job enqueueing, and it aligns promise semantics for state and result handling, while preserving existing Await and scheduler behavior. All new entry points follow the same fail-closed safety model for invalid lifecycle or ownership conditions.

The changes were delivered incrementally with focused positive and negative-path tests for execution limits, enqueue validation, and error propagation across the Go/C boundary. The full test suite passes, and total coverage remains at 100.0%.

buke added 5 commits May 22, 2026 22:03
- add runtime job queue APIs for pending checks, pending context lookup, and executing one pending job
- add context promise primitives including PromiseCapability, NewPromiseCapability, NewSettledPromise, and EnqueueJob alias
- add focused runtime/context tests for normal and fail-closed paths while keeping full coverage green
- add runtime APIs for promise hook and host promise rejection tracker with owner/liveness fail-closed behavior
- bridge quickjs promise hook and host rejection tracker callbacks from C into Go runtime dispatch
- add runtime tests for callback lifecycle, fail-closed behavior, and dispatch guard paths while preserving full coverage
- align Value.PromiseState with quickjs-ng semantics by returning PromiseNotAPromise for non-promise values
- add Value.PromiseResult to expose native JS_PromiseResult behavior for fulfilled, rejected, pending, and non-promise values
- update context/value tests to cover the new semantics and PromiseResult API while keeping full coverage at 100%
- add Runtime.DrainPendingJobs(max) to drain pending jobs with optional execution limit
- propagate job execution errors with context exception fallback semantics
- add runtime tests for limit, full drain, error path, and fail-closed behavior while preserving full coverage
- add Context.EnqueueNativeJob to enqueue callable jobs through QuickJS native JS_EnqueueJob
- introduce bridge helper EnqueueCallableJob with callable validation and JS call dispatch in native job callback
- add context promise primitive tests for enqueue success, thrown job errors, and fail-closed guards while keeping full coverage
@codecov
Copy link
Copy Markdown

codecov Bot commented May 23, 2026

Codecov Report

❌ Patch coverage is 99.39759% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 99.94%. Comparing base (1d5c2cf) to head (5a042f1).

Files with missing lines Patch % Lines
value.go 90.00% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##              main     #751      +/-   ##
===========================================
- Coverage   100.00%   99.94%   -0.06%     
===========================================
  Files           17       17              
  Lines         3831     3989     +158     
===========================================
+ Hits          3831     3987     +156     
- Misses           0        2       +2     
Files with missing lines Coverage Δ
callback_dispatch.go 100.00% <100.00%> (ø)
context.go 100.00% <100.00%> (ø)
runtime.go 100.00% <100.00%> (ø)
value.go 99.73% <90.00%> (-0.27%) ⬇️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1d5c2cf...5a042f1. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces comprehensive support for promise hooks, host promise rejection tracking, and enhanced job queue management in the QuickJS Go bindings. Key additions include NewPromiseCapability and NewSettledPromise for advanced promise control, as well as DrainPendingJobs and EnqueueNativeJob for finer execution scheduling. Review feedback suggests refining the job execution counter in DrainPendingJobs to ensure it accurately reflects the number of tasks processed and adding explicit exception checks when creating promise capabilities to prevent the use of invalid handles.

Comment thread runtime.go Outdated
Comment thread context.go
- count DrainPendingJobs executions per processed job iteration for clearer semantics
- return nil from NewPromiseCapability when JS_NewPromiseCapability reports an exception
- add a focused low-memory regression test to cover the capability exception path while preserving 100.0% total coverage
@buke
Copy link
Copy Markdown
Owner Author

buke commented May 23, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly expands the promise and job queue management capabilities of the library. It introduces support for runtime-level promise hooks, host promise rejection tracking, and the ability to enqueue native jobs directly into the QuickJS queue. New API methods such as EnqueueNativeJob, NewPromiseCapability, and DrainPendingJobs have been added, along with corresponding C bridge implementations and comprehensive unit tests. The review feedback highlights an opportunity to optimize memory allocations in EnqueueNativeJob to reduce GC pressure and suggests adding safeguards or documentation regarding potential infinite loops when draining the job queue without a limit.

Comment thread context.go
Comment thread runtime.go
@buke
Copy link
Copy Markdown
Owner Author

buke commented May 23, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces comprehensive support for promise lifecycle hooks, host rejection tracking, and native job enqueuing. Key additions include EnqueueNativeJob, NewPromiseCapability, and NewSettledPromise in the Context type, alongside job queue management methods such as DrainPendingJobs in the Runtime type. Feedback identifies potential issues with context resolution during exceptions in ExecutePendingJob, suggests earlier validation for callable jobs in EnqueueCallableJob, and recommends ensuring no reference leaks occur in NewPromiseCapability upon failure. Additionally, it is noted that DrainPendingJobs side-effects the context by clearing exceptions, which should be documented.

Comment thread runtime.go
Comment on lines +993 to +997
status := int(C.JS_ExecutePendingJob(r.ref, &ctxRef))
if ctxRef == nil {
return status, nil
}
return status, getContextFromJS(ctxRef)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

In ExecutePendingJob, if status < 0 (indicating an exception), the code attempts to resolve the Context via getContextFromJS(ctxRef). If the context is not found in the internal mapping (e.g., due to a race condition during shutdown or an external context creation), it returns nil for the context. This makes it impossible for the caller to retrieve or clear the exception, potentially leaving the runtime in an inconsistent state. Consider adding a fallback or a warning if the context cannot be resolved when an exception is reported.

Comment thread bridge.c
Comment on lines +383 to +385
if (!ctx || argc < 1 || !argv) {
return -1;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The EnqueueCallableJob function does not validate if argv[0] is actually a function before enqueuing. While the job function QuickjsGoCallableJob performs this check during execution, enqueuing a non-callable value will lead to a TypeError being raised asynchronously in the job queue. It is better to validate this early to provide immediate feedback to the caller.

Comment thread context.go
Comment on lines +1512 to +1514
if bool(C.JS_IsException(promise)) {
return nil
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When JS_NewPromiseCapability fails and returns JS_EXCEPTION, the resolving array might contain partially initialized JSValue objects if the engine failed after creating one of the functions but before completing the capability. Although QuickJS usually handles internal cleanup, it is safer to explicitly check for exceptions and ensure no leaked references remain in the resolving array if the call fails.

Comment thread runtime.go
Comment on lines +1028 to +1031
err = errors.New("quickjs: failed to execute pending job")
if ctx != nil && ctx.HasException() {
err = ctx.Exception()
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

In DrainPendingJobs, when an error occurs (status < 0), the code calls ctx.Exception() which clears the exception from the QuickJS context. While this is necessary to convert the exception to a Go error, it means that subsequent calls to DrainPendingJobs or other error-checking methods on the same context will not see the original exception. This behavior should be clearly documented as it side-effects the state of the Context.

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.

1 participant