From fbeb5eb0fc01c6b7c77e3252b75e9b1639c5ac33 Mon Sep 17 00:00:00 2001 From: Matthias Tylkowski Date: Sat, 10 May 2025 13:46:00 +0200 Subject: [PATCH 1/8] added Dockerfile --- Dockerfile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a24ebfd --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +# Use the official Node.js 22 Alpine image as the base image +FROM node:22-alpine + +# Set the working directory inside the container +WORKDIR /usr/src/app + +# Install the tileblaster package globally +RUN npm install -g tileblaster + +# Set the entry point to run tileblaster with customizable parameters +ENTRYPOINT ["node", "tileblaster"] + +# Allow users to pass additional arguments +CMD [] \ No newline at end of file From 1b5be32c5f5a4040bcf7bb15bec389fe2d30fd18 Mon Sep 17 00:00:00 2001 From: Matthias Tylkowski Date: Sat, 10 May 2025 14:08:37 +0200 Subject: [PATCH 2/8] add missing packages --- Dockerfile | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index a24ebfd..9f62acc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,7 @@ -# Use the official Node.js 22 Alpine image as the base image FROM node:22-alpine - -# Set the working directory inside the container WORKDIR /usr/src/app +RUN apk add --no-cache python3 make gcc g++ libc6-compat +RUN npm install tileblaster -# Install the tileblaster package globally -RUN npm install -g tileblaster - -# Set the entry point to run tileblaster with customizable parameters -ENTRYPOINT ["node", "tileblaster"] - -# Allow users to pass additional arguments +ENTRYPOINT ["node", "node_modules/tileblaster/bin/tileblaster.js"] CMD [] \ No newline at end of file From 72bdfd72df5c38a4cf9a3423d6aab28e027969d1 Mon Sep 17 00:00:00 2001 From: Matthias Tylkowski Date: Sun, 11 May 2025 08:01:19 +0200 Subject: [PATCH 3/8] finalize Dockerfile --- Dockerfile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9f62acc..1a9fab2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,8 @@ FROM node:22-alpine WORKDIR /usr/src/app -RUN apk add --no-cache python3 make gcc g++ libc6-compat -RUN npm install tileblaster +RUN apk add --no-cache python3 make g++ +COPY . . +RUN npm install -ENTRYPOINT ["node", "node_modules/tileblaster/bin/tileblaster.js"] +ENTRYPOINT ["node", "./bin/tileblaster.js"] CMD [] \ No newline at end of file From 1dc4cc4c1b2915af9e01ca72b57efd7d5d7e2c14 Mon Sep 17 00:00:00 2001 From: Matthias Tylkowski Date: Sun, 11 May 2025 08:01:30 +0200 Subject: [PATCH 4/8] add dokumentation --- readme.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/readme.md b/readme.md index 03e2333..7126f04 100644 --- a/readme.md +++ b/readme.md @@ -40,6 +40,10 @@ if you're allowed to do so. * `-v` `--verbose` - enable debug output * `-q` `--quiet` - disable debug output +## Docker usage +`docker build . -t tileblaster` +`docker run -v :/usr/src/app/config.js tileblaster -c ./config.js -v` + ## Configuration See [Configuration](docs/config.md) and [Examples](docs/examples.md) From 386eb36bcd6092b167bf7b4e8720e1dc1ae0d923 Mon Sep 17 00:00:00 2001 From: Matthias Tylkowski Date: Sun, 11 May 2025 19:25:39 +0200 Subject: [PATCH 5/8] optimize Dockerfile for caching --- Dockerfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 1a9fab2..a63cc73 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,13 @@ FROM node:22-alpine WORKDIR /usr/src/app RUN apk add --no-cache python3 make g++ -COPY . . + +# Copy package.json and package-lock.json first to leverage caching +COPY package*.json ./ RUN npm install +# Copy the rest of the application files +COPY . . + ENTRYPOINT ["node", "./bin/tileblaster.js"] CMD [] \ No newline at end of file From ade9bf5a521e04136855010cf9e4a278cfd56859 Mon Sep 17 00:00:00 2001 From: Matthias Tylkowski Date: Thu, 21 Aug 2025 08:34:38 +0200 Subject: [PATCH 6/8] added .dockerignore --- .dockerignore | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ffca305 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,69 @@ +# Version control +.git +.gitignore + +# Node.js +node_modules +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.npm + +# Development files +.dockerignore +Dockerfile* +docker-compose*.yml +.env.local +.env.development.local +.env.test.local +.env.production.local + +# IDE and editor files +.vscode +.idea +*.swp +*.swo +*~ +.nova + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage + +# Documentation +docs/ +readme.md +*.md + +# Config and temporary files +config.js +*.socket +attic + +# Test files +test/ +tests/ +*.test.js +*.spec.js + +# Build artifacts +dist/ +build/ From 0584bdd88e1730a79ef01149339ac1616377c950 Mon Sep 17 00:00:00 2001 From: Matthias Tylkowski Date: Thu, 21 Aug 2025 08:37:16 +0200 Subject: [PATCH 7/8] check if cache.dir exists before walking it --- lib/purge.js | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/lib/purge.js b/lib/purge.js index 0b4414b..bfec0ef 100644 --- a/lib/purge.js +++ b/lib/purge.js @@ -84,20 +84,31 @@ if (worker.isMainThread) { Promise.allSettled(caches.map(function(cache){ return new Promise(function(resolve,reject){ - let deletable = []; - - klaw(cache.dir).on("data", function(file){ - if (file.stats.mtimeMs > cache.expires) deletable.push(file.path); - }).on("end", function(){ - Promise.allSettled(deletable.map(function(file){ - return new Promise(function(resolve,reject){ - fs.unlink(file, function(err){ - if (err) return reject(err); - purged++; - resolve(); + // check if directory exists before trying to walk it + fs.access(cache.dir, fs.constants.F_OK, function(err){ + if (err) { + // directory doesn't exist, nothing to purge + return resolve(); + } + + let deletable = []; + + klaw(cache.dir).on("data", function(file){ + if (file.stats.mtimeMs > cache.expires) deletable.push(file.path); + }).on("end", function(){ + Promise.allSettled(deletable.map(function(file){ + return new Promise(function(resolve,reject){ + fs.unlink(file, function(err){ + if (err) return reject(err); + purged++; + resolve(); + }); }); - }); - })).then(resolve).catch(reject); + })).then(resolve).catch(reject); + }).on("error", function(err){ + // handle klaw errors gracefully + reject(err); + }); }); }); })).then(function(){ From 866c77476547215f02cfe84c281e63bbedcba4b3 Mon Sep 17 00:00:00 2001 From: Matthias Tylkowski Date: Thu, 21 Aug 2025 08:40:14 +0200 Subject: [PATCH 8/8] handle EADDRINUSE error --- bin/tileblaster.js | 13 +++++++++++++ tileblaster.js | 31 +++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/bin/tileblaster.js b/bin/tileblaster.js index cc63b6f..91aebef 100755 --- a/bin/tileblaster.js +++ b/bin/tileblaster.js @@ -19,6 +19,19 @@ if (require.main === module) { function fork(n){ worker = cluster.fork({ ...process.env, workerid: n }); debug.info("Started Worker #%d".bold.white, n); + + // Handle messages from workers + worker.on('message', function(message) { + if (typeof message === 'object' && message.type === 'fatal-error') { + debug.error("Worker #%d reported fatal error: %s".bold.red, n, message.message); + if (message.error === 'EADDRINUSE') { + debug.error("Address already in use - initiating complete shutdown".bold.red); + shutdown(); + return; + } + } + }); + worker.on('disconnect', function(){ debug.warn("Disconnect from Worker #%d".bold.white, n); if (shuttingdown) { // remove worker from pool diff --git a/tileblaster.js b/tileblaster.js index 6b67271..e9bff39 100644 --- a/tileblaster.js +++ b/tileblaster.js @@ -434,10 +434,30 @@ tileblaster.prototype.listen = function(router){ router.call(self.router, ...arguments); }); + // Handle server errors (like EADDRINUSE) before they become unhandled + server.on('error', function(err) { + debug.error("Server error:", err); + if (err.code === 'EADDRINUSE') { + debug.error("Address already in use, starting shutdown process"); + // Notify main process about fatal error before shutting down + if (process.send) { + process.send({ type: 'fatal-error', error: 'EADDRINUSE', message: 'Address already in use' }); + } + self.shutdown(); + } + }); + if (listen.port) { server.listen(listen.port, listen.host, function(err){ - if (err) return debug.error("listen: ERROR binding port '%s:%d':", listen.host, listen.port, err); + if (err) { + debug.error("listen: ERROR binding port '%s:%d':", listen.host, listen.port, err); + if (err.code === 'EADDRINUSE') { + debug.error("Port %d is already in use, starting shutdown process", listen.port); + self.shutdown(); + } + return; + } debug.info("Listening on '%s:%d'", listen.host, listen.port); self.servers.push(server); }); @@ -459,7 +479,14 @@ tileblaster.prototype.listen = function(router){ if (err && err.code !== "ENOENT") return debug.error("Deleting socket '%s':", listen.socket, err); server.listen(listen.socket, function(err) { - if (err) return debug.error("Binding to socket '%s':", listen.socket, err); + if (err) { + debug.error("Binding to socket '%s':", listen.socket, err); + if (err.code === 'EADDRINUSE') { + debug.error("Socket %s is already in use, starting shutdown process", listen.socket); + self.shutdown(); + } + return; + } // store socket path server.socket = listen.socket;