Stop an export, a load or a save that your server no longer needs, or give it
a deadline, with a standard AbortSignal in the native Node.js bindings.
Exports, loads, downloads and saves go on in the engine after the call returns. When a client disconnects or a job
runs out of time, your server no longer needs that work. Each call of @cesdk/node-native that exports, loads,
downloads or saves takes an abortSignal option. An abort ends the call at once, stops its work in the engine and
frees what it holds. On the server you cancel in code, because there is no user interface.
This guide covers how to cancel a call, which calls you can cancel, how to give a call a deadline, how to cancel from a progress callback, and what the engine keeps after a cancel.
Cancelling a Call#
Create an AbortController and pass its signal as abortSignal in the options of the call. Call
controller.abort() to cancel. The promise rejects with Error('AbortSignal received').
The script below builds a page with an image block, starts a PNG export of the page and aborts it right away.
import CreativeEngine from '@cesdk/node-native';
const engine = await CreativeEngine.init({ license: 'YOUR_CESDK_LICENSE_KEY' });
try { const scene = engine.scene.create(); const page = engine.block.create('page'); engine.block.setWidth(page, 800); engine.block.setHeight(page, 600); engine.block.appendChild(scene, page);
const imageBlock = engine.block.create('graphic'); engine.block.setShape(imageBlock, engine.block.createShape('rect')); const imageFill = engine.block.createFill('image'); engine.block.setString( imageFill, 'fill/image/imageFileURI', 'https://img.ly/static/ubq_samples/sample_1.jpg' ); engine.block.setFill(imageBlock, imageFill); engine.block.setWidth(imageBlock, 800); engine.block.setHeight(imageBlock, 600); engine.block.appendChild(page, imageBlock);
const controller = new AbortController(); const exporting = engine.block.export(page, { mimeType: 'image/png', abortSignal: controller.signal }); controller.abort();
try { await exporting; console.log('The export ended before the abort'); } catch (error) { // Logs "AbortSignal received" console.log('The export stopped:', error.message); }} finally { engine.dispose();}A signal that aborted before the call rejects at once, and the call starts nothing. A call that has already settled ignores the abort.
Calls That Can Be Cancelled#
Each of these calls takes abortSignal in its options object, which is its last argument. In
engine.scene.createFromImage() the options object is the seventh argument, after spacingInScreenSpace. In
engine.block.saveToString() it is the fourth, after onDisallowedResourceScheme.
- Exports:
engine.block.export()(images and PDF),engine.block.exportWithColorMask(),engine.block.exportVideo(),engine.block.exportAudio() - Scene and block loads:
engine.scene.load(),engine.scene.loadFromURL(),engine.scene.loadFromString()withwaitForResources,engine.scene.loadFromArchiveURL(),engine.scene.applyTemplateFromURL(),engine.block.loadFromURL(),engine.block.loadFromArchiveURL() - New scenes from media:
engine.scene.createFromImage(),engine.scene.createFromVideo() - Downloads for a block or an asset:
engine.block.createCaptionsFromURI(),engine.block.addImageFileURIToSourceSet(),engine.block.addVideoFileURIToSourceSet(),engine.block.forceLoadAVResource(),engine.block.forceLoadResources(),engine.asset.addLocalAssetSourceFromJSONURI(),engine.asset.apply(),engine.asset.defaultApplyAsset() - Lookups:
engine.editor.getMimeType(),engine.editor.getFontMetrics(),engine.block.getDominantColors() - Color profiles:
engine.scene.setCMYKProfile(),engine.editor.loadCMYKProfile() - Saves:
engine.scene.saveToArchive(),engine.block.saveToArchive(), andengine.scene.saveToString()orengine.block.saveToString()while they wait foronDisallowedResourceScheme
Giving a Call a Deadline#
Pass AbortSignal.timeout(ms) as abortSignal. The engine has no timeout of its own, so the signal is the
deadline. Here we give a scene load ten seconds.
const deadline = AbortSignal.timeout(10_000);try { await engine.scene.load( 'https://cdn.img.ly/assets/demo/v3/ly.img.template/templates/cesdk_postcard_1.scene', { abortSignal: deadline } ); console.log('The scene loaded in time');} catch (error) { if (!deadline.aborted) { throw error; } console.log('The scene did not load within 10 seconds');}A deadline rejects with the same AbortSignal received error as abort(). Check aborted on the signal to tell
a missed deadline from a failed download, and throw every other error again.
Cancelling From a Progress Callback#
You can call controller.abort() inside onProgress of exportVideo() or exportAudio(). Here we stop a video
export that has rendered less than half of its frames after one minute.
const controller = new AbortController();const startedAt = Date.now();try { const blob = await engine.block.exportVideo(page, { mimeType: 'video/mp4', abortSignal: controller.signal, onProgress: (renderedFrames, encodedFrames, totalFrames) => { const elapsed = Date.now() - startedAt; if (elapsed > 60_000 && renderedFrames < totalFrames / 2) { controller.abort(); } } }); console.log(`The video file has ${blob.size} bytes`);} catch (error) { if (!controller.signal.aborted) { throw error; } console.log('The export was too slow and stopped');}No progress report follows the abort, and the next export can start at once. The time of the first reports includes the start-up of the export, so a projection of the total time from them would stop fast exports too.
What a Cancel Stops and What It Keeps#
A cancel stops the work of the call, but the engine keeps what other blocks and calls still need:
- A video export and an audio export that mixes a page stop at once and release their encoders.
- An image or PDF export frees its document in the next engine update.
- An audio export that copies the audio of one block without the mixer finishes the copy in the background and drops it.
- A load stops its download, unless a block or another call needs the same file. The engine reads every video fill at each update, so the download of a video fill goes on.
load()andloadFromURL()keep the current scene. WithwaitForResourcesthe new scene replaces it before the wait for its resources, so a cancel during that wait keeps the new scene.loadFromString()withwaitForResourcesloads the scene at once, so a cancel ends only the wait.loadCMYKProfile()ends only the wait, because the document keeps its profile loaded.- A cancelled
setCMYKProfile()gives back its claim, so an assignment that it replaced still takes effect. - An answer of
onDisallowedResourceSchemeafter the abort changes nothing. asset.apply()stops the download that the default apply waits for, so it creates no block. An asset source with its ownapplyAssetkeeps running in your code. A block that it creates stays, and the call does not return it.getDominantColors()waits while a resource of the block loads, so a signal gives it a deadline.
Starting the Next Call#
After the promise rejects, the engine is free for the next export or load. Start it in the rejection handler or
after the await. Here we export the page again, this time without a signal. Put these lines in the outer try
block of the first script, after the cancelled export. Its finally block disposes the engine.
const blob = await engine.block.export(page, { mimeType: 'image/png' });console.log(`The next export made a PNG file of ${blob.size} bytes`);The second export waits for the image that the first export waited for, because the image block still needs it.
Start an audio export after the running audio export settles, not inside its progress callback.
Troubleshooting#
- The promise rejects with
AbortSignal receivedat once: The signal aborted before the call. Create a newAbortControllerfor each call. - The promise resolves although you aborted: The call ended before the abort.
- The download of a cancelled load goes on: Another block or another call needs the same file.
- A call rejects with a validation error for
abortSignal: The option must be anAbortSignal, not a boolean or a string.
API Reference#
These are the methods this guide calls. The section Calls That Can Be Cancelled lists every method that takes
abortSignal.
| Method | Category | Purpose |
|---|---|---|
engine.block.export() |
Block | Export a block as an image or a PDF |
engine.block.exportVideo() |
Block | Export a page as a video |
engine.scene.load() |
Scene | Load a scene or an archive from a URL or a string |
Next Steps#
- Export - Export designs and videos
- Resources - Learn how the engine loads files
- Scenes - Load and save scenes
- Error Catalog - Look up engine error codes