tileserver-gl-light 5.5.0-pre.4 → 5.5.0-pre.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +2 -1
- package/package.json +3 -3
- package/src/serve_rendered.js +48 -27
package/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# tileserver-gl changelog
|
|
2
2
|
|
|
3
|
-
## 5.5.0-pre.
|
|
3
|
+
## 5.5.0-pre.5
|
|
4
4
|
* Add S3 support for PMTiles with multiple AWS credential profiles (https://github.com/maptiler/tileserver-gl/pull/1779) by @acalcutt
|
|
5
5
|
* Create .aws directory passthrough folder in Dockerfile (https://github.com/maptiler/tileserver-gl/pull/1784) by @acalcutt
|
|
6
6
|
* Update eslint to v9 (https://github.com/maptiler/tileserver-gl/pull/1473) by @acalcutt
|
|
7
7
|
* Fix Renderer Crashes from Failed Fetches (https://github.com/maptiler/tileserver-gl/pull/1798) by @acalcutt
|
|
8
8
|
* Add Visual Regression Tests for Static Image Overlays (https://github.com/maptiler/tileserver-gl/pull/1792) by @acalcutt
|
|
9
9
|
* Fix S3 URL parsing for nested paths in AWS buckets (https://github.com/maptiler/tileserver-gl/pull/1819) by @acalcutt
|
|
10
|
+
* Fix Renderer Crashes and Memory Leak (https://github.com/maptiler/tileserver-gl/pull/1825) by @acalcutt
|
|
10
11
|
|
|
11
12
|
## 5.4.0
|
|
12
13
|
* Fix the issue where the tile URL cannot be correctly parsed with the HTTPS protocol when using an nginx proxy service (https://github.com/maptiler/tileserver-gl/pull/1578) by @dakanggo
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tileserver-gl-light",
|
|
3
|
-
"version": "5.5.0-pre.
|
|
3
|
+
"version": "5.5.0-pre.5",
|
|
4
4
|
"description": "Map tile server for JSON GL styles - serving vector tiles",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"bin": "src/main.js",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"docker": "docker build . && docker run --rm -i -p 8080:8080 $(docker build -q .)"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@aws-sdk/client-s3": "^3.
|
|
38
|
+
"@aws-sdk/client-s3": "^3.935.0",
|
|
39
39
|
"@jsse/pbfont": "^0.3.0",
|
|
40
40
|
"@mapbox/mapbox-gl-rtl-text": "0.3.0",
|
|
41
41
|
"@mapbox/mbtiles": "0.12.1",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"morgan": "1.10.1",
|
|
62
62
|
"pbf": "4.0.1",
|
|
63
63
|
"pmtiles": "4.3.0",
|
|
64
|
-
"proj4": "2.20.
|
|
64
|
+
"proj4": "2.20.2",
|
|
65
65
|
"sanitize-filename": "1.6.3",
|
|
66
66
|
"semver": "^7.7.3",
|
|
67
67
|
"tileserver-gl-styles": "2.0.0"
|
package/src/serve_rendered.js
CHANGED
|
@@ -531,30 +531,43 @@ async function respondImage(
|
|
|
531
531
|
pool = item.map.renderersStatic[scale];
|
|
532
532
|
}
|
|
533
533
|
|
|
534
|
+
if (!pool) {
|
|
535
|
+
console.error(`Pool not found for scale ${scale}, mode ${mode}`);
|
|
536
|
+
return res.status(500).send('Renderer pool not configured');
|
|
537
|
+
}
|
|
538
|
+
|
|
534
539
|
pool.acquire(async (err, renderer) => {
|
|
535
540
|
// Check if pool.acquire failed or returned null/invalid renderer
|
|
536
541
|
if (err) {
|
|
537
542
|
console.error('Failed to acquire renderer from pool:', err);
|
|
538
|
-
|
|
543
|
+
if (!res.headersSent) {
|
|
544
|
+
return res.status(503).send('Renderer pool error');
|
|
545
|
+
}
|
|
546
|
+
return;
|
|
539
547
|
}
|
|
540
548
|
|
|
541
549
|
if (!renderer) {
|
|
542
550
|
console.error(
|
|
543
551
|
'Renderer is null - likely crashed or failed to initialize',
|
|
544
552
|
);
|
|
545
|
-
|
|
553
|
+
if (!res.headersSent) {
|
|
554
|
+
return res.status(503).send('Renderer unavailable');
|
|
555
|
+
}
|
|
556
|
+
return;
|
|
546
557
|
}
|
|
547
558
|
|
|
548
559
|
// Validate renderer has required methods (basic health check)
|
|
549
560
|
if (typeof renderer.render !== 'function') {
|
|
550
561
|
console.error('Renderer is invalid - missing render method');
|
|
551
|
-
// Destroy the bad renderer and remove from pool
|
|
552
562
|
try {
|
|
553
|
-
pool.
|
|
563
|
+
pool.removeBadObject(renderer);
|
|
554
564
|
} catch (e) {
|
|
555
|
-
console.error('Error
|
|
565
|
+
console.error('Error removing bad renderer:', e);
|
|
556
566
|
}
|
|
557
|
-
|
|
567
|
+
if (!res.headersSent) {
|
|
568
|
+
return res.status(503).send('Renderer invalid');
|
|
569
|
+
}
|
|
570
|
+
return;
|
|
558
571
|
}
|
|
559
572
|
|
|
560
573
|
// For 512px tiles, use the actual maplibre-native zoom. For 256px tiles, use zoom - 1
|
|
@@ -588,13 +601,14 @@ async function respondImage(
|
|
|
588
601
|
|
|
589
602
|
// Set a timeout for the render operation to detect hung renderers
|
|
590
603
|
const renderTimeout = setTimeout(() => {
|
|
591
|
-
console.error('Renderer timeout - destroying
|
|
604
|
+
console.error('Renderer timeout - destroying hung renderer');
|
|
605
|
+
|
|
592
606
|
try {
|
|
593
|
-
|
|
594
|
-
pool.destroy(renderer);
|
|
607
|
+
pool.removeBadObject(renderer);
|
|
595
608
|
} catch (e) {
|
|
596
|
-
console.error('Error
|
|
609
|
+
console.error('Error removing timed-out renderer:', e);
|
|
597
610
|
}
|
|
611
|
+
|
|
598
612
|
if (!res.headersSent) {
|
|
599
613
|
res.status(503).send('Renderer timeout');
|
|
600
614
|
}
|
|
@@ -604,13 +618,17 @@ async function respondImage(
|
|
|
604
618
|
renderer.render(params, (err, data) => {
|
|
605
619
|
clearTimeout(renderTimeout);
|
|
606
620
|
|
|
621
|
+
if (res.headersSent) {
|
|
622
|
+
// Timeout already fired and sent response, don't process
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
|
|
607
626
|
if (err) {
|
|
608
627
|
console.error('Render error:', err);
|
|
609
|
-
// Destroy renderer instead of releasing it back to pool since it may be corrupted
|
|
610
628
|
try {
|
|
611
|
-
pool.
|
|
629
|
+
pool.removeBadObject(renderer);
|
|
612
630
|
} catch (e) {
|
|
613
|
-
console.error('Error
|
|
631
|
+
console.error('Error removing failed renderer:', e);
|
|
614
632
|
}
|
|
615
633
|
if (!res.headersSent) {
|
|
616
634
|
return res
|
|
@@ -646,12 +664,11 @@ async function respondImage(
|
|
|
646
664
|
height: height * scale,
|
|
647
665
|
});
|
|
648
666
|
}
|
|
649
|
-
// HACK(Part 2) 256px tiles are a zoom level lower than maplibre-native default tiles. this hack allows tileserver-gl to support zoom 0 256px tiles, which would actually be zoom -1 in maplibre-native. Since zoom -1 isn't supported, a double sized zoom 0 tile is requested and resized here.
|
|
650
667
|
|
|
668
|
+
// HACK(Part 2) 256px tiles are a zoom level lower than maplibre-native default tiles. this hack allows tileserver-gl to support zoom 0 256px tiles, which would actually be zoom -1 in maplibre-native. Since zoom -1 isn't supported, a double sized zoom 0 tile is requested and resized here.
|
|
651
669
|
if (z === 0 && width === 256) {
|
|
652
670
|
image.resize(width * scale, height * scale);
|
|
653
671
|
}
|
|
654
|
-
// END HACK(Part 2)
|
|
655
672
|
|
|
656
673
|
const composites = [];
|
|
657
674
|
if (overlay) {
|
|
@@ -659,7 +676,6 @@ async function respondImage(
|
|
|
659
676
|
}
|
|
660
677
|
if (item.watermark) {
|
|
661
678
|
const canvas = renderWatermark(width, height, scale, item.watermark);
|
|
662
|
-
|
|
663
679
|
composites.push({ input: canvas.toBuffer() });
|
|
664
680
|
}
|
|
665
681
|
|
|
@@ -670,7 +686,6 @@ async function respondImage(
|
|
|
670
686
|
scale,
|
|
671
687
|
item.staticAttributionText,
|
|
672
688
|
);
|
|
673
|
-
|
|
674
689
|
composites.push({ input: canvas.toBuffer() });
|
|
675
690
|
}
|
|
676
691
|
|
|
@@ -687,7 +702,6 @@ async function respondImage(
|
|
|
687
702
|
}
|
|
688
703
|
// eslint-disable-next-line security/detect-object-injection -- format is validated above
|
|
689
704
|
const formatQuality = formatQualities[format];
|
|
690
|
-
|
|
691
705
|
// eslint-disable-next-line security/detect-object-injection -- format is validated above
|
|
692
706
|
const formatOptions = (options.formatOptions || {})[format] || {};
|
|
693
707
|
|
|
@@ -710,25 +724,32 @@ async function respondImage(
|
|
|
710
724
|
} else if (format === 'webp') {
|
|
711
725
|
image.webp({ quality: formatOptions.quality || formatQuality || 90 });
|
|
712
726
|
}
|
|
727
|
+
|
|
713
728
|
image.toBuffer((err, buffer, info) => {
|
|
714
|
-
if (!buffer) {
|
|
715
|
-
|
|
729
|
+
if (err || !buffer) {
|
|
730
|
+
console.error('Sharp error:', err);
|
|
731
|
+
if (!res.headersSent) {
|
|
732
|
+
return res.status(500).send('Image processing failed');
|
|
733
|
+
}
|
|
734
|
+
return;
|
|
716
735
|
}
|
|
717
736
|
|
|
718
|
-
res.
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
737
|
+
if (!res.headersSent) {
|
|
738
|
+
res.set({
|
|
739
|
+
'Last-Modified': item.lastModified,
|
|
740
|
+
'Content-Type': `image/${format}`,
|
|
741
|
+
});
|
|
742
|
+
return res.status(200).send(buffer);
|
|
743
|
+
}
|
|
723
744
|
});
|
|
724
745
|
});
|
|
725
746
|
} catch (error) {
|
|
726
747
|
clearTimeout(renderTimeout);
|
|
727
748
|
console.error('Unexpected error during render:', error);
|
|
728
749
|
try {
|
|
729
|
-
pool.
|
|
750
|
+
pool.removeBadObject(renderer);
|
|
730
751
|
} catch (e) {
|
|
731
|
-
console.error('Error
|
|
752
|
+
console.error('Error removing renderer after error:', e);
|
|
732
753
|
}
|
|
733
754
|
if (!res.headersSent) {
|
|
734
755
|
return res.status(500).send('Render failed');
|