Skip to content

Conversation

@ViktorVovk
Copy link
Contributor

The main goal of this PR is to propagate exceptions from loadResources back to the resource managers when a loading error occurs, so that the processAndRetryIfNeededWithPromisePool retry logic can be applied.

Typically, resources are downloaded from a CDN, and sometimes, for various reasons, a request for a resource may fail. In such cases, it’s very useful to have retry logic for downloads — and luckily, you already have it implemented. However, the resource managers did not propagate the thrown errors, which is required for processAndRetryIfNeededWithPromisePool to work correctly.

In addition, I took the liberty of making processAndRetryIfNeededWithPromisePool and processWithPromisePool static methods of the ResourceLoader class. This makes it possible to reuse these functions in client code without having to duplicate them.

I’d be grateful for a review and any feedback.
Best regards,
Viktor

Viktor Vovk added 2 commits December 11, 2025 14:18
… thrown after logging. This includes updates to the PIXI spine, JSON, Model3D, font face observer, sound, and image managers to improve robustness and error reporting.
- Moved processWithPromisePool and processAndRetryIfNeededWithPromisePool to static methods for better organization.
- Introduced PromiseError and PromisePoolOutput types for enhanced error management.
- Updated calls to processAndRetryIfNeededWithPromisePool to use the new static method reference.
@ViktorVovk ViktorVovk requested a review from 4ian as a code owner December 11, 2025 12:48
Copy link
Owner

@4ian 4ian left a comment

Choose a reason for hiding this comment

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

Hello! Thank your for submitting this. Overall I think it's indeed much better to fix these loading methods by allowing them to throw and have the caller properly retry as intended. Good catch :)

I've added a few comments and questions.


async loadResource(resourceName: string): Promise<void> {
await this.getOrLoad(resourceName);
try {
Copy link
Owner

Choose a reason for hiding this comment

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

This one might be unnecessary unless you have an idea like making it very clear it can throw?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You are right! it was excessive! Thanks
Fixed!

if (sound.status >= 200 && sound.status < 300) {
resolve(undefined);
} else {
reject(`HTTP error! status: ${sound.status}`);
Copy link
Owner

Choose a reason for hiding this comment

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

I suggest an exception that gives more context to ease debugging:

Suggested change
reject(`HTTP error! status: ${sound.status}`);
reject(`HTTP error while preloading audio file in cache. Status is ${sound.status}.`);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

}
);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
throw new Error(`HTTP error! status: ${response.status}`);
throw new Error(`HTTP error while loading bitmap font. Status is ${sound.status}.`);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

}
await this._loadTexture(resource);

try {
Copy link
Owner

Choose a reason for hiding this comment

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

Same comment here: this looks unnecessary?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed! Thanks

}
} catch (error) {
logFileLoadingError(resource.file, error);
PIXI.Texture.removeFromCache(resourceUrl);
Copy link
Owner

Choose a reason for hiding this comment

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

Have you observed this to be useful? I wonder if this will work because the internal texture id used by PixiJS could be different than the resourceUrl?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I’ve checked that. This is needed so that PIXI.Texture.from performs a new network request and cancels caching of the previous result. I think in this context the URL is the unique identifier of the resource.

Viktor Vovk added 2 commits December 12, 2025 11:52
- Moved maxForegroundConcurrency, maxBackgroundConcurrency, and maxAttempt to static properties of ResourceLoader for better organization and accessibility.
- Updated references throughout the ResourceLoader class to use the new static properties.
- Removed unnecessary try-catch blocks in the PIXI spine atlas and image managers, allowing errors to propagate naturally.
- Enhanced error messages in the sound and bitmap font managers for clearer debugging information when HTTP errors occur.
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.

2 participants