Skip to content

Commit 1f50067

Browse files
committed
feat: allow process to be started using instance_id
to be able to launch multiple instances of npm in the same node_modules dir. Refs: #2462
1 parent 2466e47 commit 1f50067

File tree

6 files changed

+54
-21
lines changed

6 files changed

+54
-21
lines changed

lib/src/main/java/com/diffplug/spotless/npm/NodeModulesCachingNpmProcessFactory.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023-2024 DiffPlug
2+
* Copyright 2023-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -18,6 +18,7 @@
1818
import java.io.File;
1919
import java.util.List;
2020
import java.util.Objects;
21+
import java.util.UUID;
2122

2223
import javax.annotation.Nonnull;
2324

@@ -65,8 +66,8 @@ public NpmProcess createNpmInstallProcess(NodeServerLayout nodeServerLayout, Npm
6566
}
6667

6768
@Override
68-
public NpmLongRunningProcess createNpmServeProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations) {
69-
return StandardNpmProcessFactory.INSTANCE.createNpmServeProcess(nodeServerLayout, formatterStepLocations);
69+
public NpmLongRunningProcess createNpmServeProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations, UUID nodeServerInstanceId) {
70+
return StandardNpmProcessFactory.INSTANCE.createNpmServeProcess(nodeServerLayout, formatterStepLocations, nodeServerInstanceId);
7071
}
7172

7273
private class CachingNmpInstall implements NpmProcess {

lib/src/main/java/com/diffplug/spotless/npm/NodeServeApp.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 DiffPlug
2+
* Copyright 2023-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
1515
*/
1616
package com.diffplug.spotless.npm;
1717

18+
import java.util.UUID;
19+
1820
import javax.annotation.Nonnull;
1921

2022
import org.slf4j.Logger;
@@ -32,9 +34,9 @@ public NodeServeApp(@Nonnull NodeServerLayout nodeServerLayout, @Nonnull NpmConf
3234
super(nodeServerLayout, npmConfig, formatterStepLocations);
3335
}
3436

35-
ProcessRunner.LongRunningProcess startNpmServeProcess() {
37+
ProcessRunner.LongRunningProcess startNpmServeProcess(UUID nodeServerInstanceId) {
3638
return timedLogger.withInfo("Starting npm based server in {} with {}.", this.nodeServerLayout.nodeModulesDir(), this.npmProcessFactory.describe())
37-
.call(() -> npmProcessFactory.createNpmServeProcess(nodeServerLayout, formatterStepLocations).start());
39+
.call(() -> npmProcessFactory.createNpmServeProcess(nodeServerLayout, formatterStepLocations, nodeServerInstanceId).start());
3840
}
3941

4042
}

lib/src/main/java/com/diffplug/spotless/npm/NpmFormatterStepStateBase.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import java.util.Iterator;
2626
import java.util.Map;
2727
import java.util.Map.Entry;
28+
import java.util.UUID;
2829
import java.util.concurrent.TimeUnit;
2930
import java.util.concurrent.TimeoutException;
3031

@@ -112,12 +113,13 @@ protected ServerProcessInfo npmRunServer() throws ServerStartException, IOExcept
112113
assertNodeServerDirReady();
113114
LongRunningProcess server = null;
114115
try {
115-
// The npm process will output the randomly selected port of the http server process to 'server.port' file
116+
final UUID nodeServerInstanceId = UUID.randomUUID();
117+
// The npm process will output the randomly selected port of the http server process to 'server-<id>.port' file
116118
// so in order to be safe, remove such a file if it exists before starting.
117-
final File serverPortFile = new File(this.nodeServerLayout.nodeModulesDir(), "server.port");
119+
final File serverPortFile = new File(this.nodeServerLayout.nodeModulesDir(), String.format("server-%s.port", nodeServerInstanceId));
118120
NpmResourceHelper.deleteFileIfExists(serverPortFile);
119121
// start the http server in node
120-
server = nodeServeApp.startNpmServeProcess();
122+
server = nodeServeApp.startNpmServeProcess(nodeServerInstanceId);
121123

122124
// await the readiness of the http server - wait for at most 60 seconds
123125
try {

lib/src/main/java/com/diffplug/spotless/npm/NpmProcessFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 DiffPlug
2+
* Copyright 2023-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
1515
*/
1616
package com.diffplug.spotless.npm;
1717

18+
import java.util.UUID;
19+
1820
public interface NpmProcessFactory {
1921

2022
enum OnlinePreferrence {
@@ -33,7 +35,7 @@ public String option() {
3335

3436
NpmProcess createNpmInstallProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations, OnlinePreferrence onlinePreferrence);
3537

36-
NpmLongRunningProcess createNpmServeProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations);
38+
NpmLongRunningProcess createNpmServeProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations, UUID nodeServerInstanceId);
3739

3840
default String describe() {
3941
return getClass().getSimpleName();

lib/src/main/java/com/diffplug/spotless/npm/StandardNpmProcessFactory.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 DiffPlug
2+
* Copyright 2023-2025 DiffPlug
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@
1919
import java.io.IOException;
2020
import java.util.List;
2121
import java.util.Map;
22+
import java.util.UUID;
2223
import java.util.concurrent.ExecutionException;
2324

2425
import com.diffplug.spotless.ProcessRunner;
@@ -37,8 +38,8 @@ public NpmProcess createNpmInstallProcess(NodeServerLayout nodeServerLayout, Npm
3738
}
3839

3940
@Override
40-
public NpmLongRunningProcess createNpmServeProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations) {
41-
return new NpmServe(nodeServerLayout.nodeModulesDir(), formatterStepLocations);
41+
public NpmLongRunningProcess createNpmServeProcess(NodeServerLayout nodeServerLayout, NpmFormatterStepLocations formatterStepLocations, UUID nodeServerInstanceId) {
42+
return new NpmServe(nodeServerLayout.nodeModulesDir(), formatterStepLocations, nodeServerInstanceId);
4243
}
4344

4445
private static abstract class AbstractStandardNpmProcess {
@@ -119,16 +120,21 @@ public ProcessRunner.Result waitFor() {
119120

120121
private static class NpmServe extends AbstractStandardNpmProcess implements NpmLongRunningProcess {
121122

122-
public NpmServe(File workingDir, NpmFormatterStepLocations formatterStepLocations) {
123+
private final UUID nodeServerInstanceId;
124+
125+
public NpmServe(File workingDir, NpmFormatterStepLocations formatterStepLocations, UUID nodeServerInstanceId) {
123126
super(workingDir, formatterStepLocations);
127+
this.nodeServerInstanceId = nodeServerInstanceId;
124128
}
125129

126130
@Override
127131
protected List<String> commandLine() {
128132
return List.of(
129133
npmExecutable(),
130134
"start",
131-
"--scripts-prepend-node-path=true");
135+
"--scripts-prepend-node-path=true",
136+
"--",
137+
"--node-server-instance-id=" + nodeServerInstanceId);
132138
}
133139

134140
@Override

lib/src/main/resources/com/diffplug/spotless/npm/common-serve.js

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const GracefulShutdownManager = require("@moebius/http-graceful-shutdown").Grace
44
const express = require("express");
55
const app = express();
66

7-
app.use(express.json({ limit: "50mb" }));
7+
app.use(express.json({limit: "50mb"}));
88

99
const fs = require("fs");
1010

@@ -14,13 +14,33 @@ function debugLog() {
1414
}
1515
}
1616

17+
function getInstanceId() {
18+
const args = process.argv.slice(2);
19+
20+
// Look for the --node-server-instance-id option
21+
let instanceId;
22+
23+
args.forEach(arg => {
24+
if (arg.startsWith('--node-server-instance-id=')) {
25+
instanceId = arg.split('=')[1];
26+
}
27+
});
28+
29+
// throw if instanceId is not set
30+
if (!instanceId) {
31+
throw new Error("Missing --node-server-instance-id argument");
32+
}
33+
return instanceId;
34+
}
35+
1736
var listener = app.listen(0, "127.0.0.1", () => {
18-
debugLog("Server running on port " + listener.address().port);
19-
fs.writeFile("server.port.tmp", "" + listener.address().port, function(err) {
37+
const instanceId = getInstanceId();
38+
debugLog("Server running on port " + listener.address().port + " for instance " + instanceId);
39+
fs.writeFile("server.port.tmp", "" + listener.address().port, function (err) {
2040
if (err) {
2141
return console.log(err);
2242
} else {
23-
fs.rename("server.port.tmp", "server.port", function(err) {
43+
fs.rename("server.port.tmp", `server-${instanceId}.port`, function (err) {
2444
if (err) {
2545
return console.log(err);
2646
}
@@ -32,7 +52,7 @@ const shutdownManager = new GracefulShutdownManager(listener);
3252

3353
app.post("/shutdown", (req, res) => {
3454
res.status(200).send("Shutting down");
35-
setTimeout(function() {
55+
setTimeout(function () {
3656
shutdownManager.terminate(() => debugLog("graceful shutdown finished."));
3757
}, 200);
3858
});

0 commit comments

Comments
 (0)