Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces three different proof-of-concept (POC) implementations for a Node.js wrapper for the Go Spanner library: an IPC-based gRPC wrapper, a Koffi-based FFI wrapper, and an N-API C++ wrapper. The changes include build scripts, setup utilities, and test suites for each approach. My feedback highlights several critical and high-severity issues, including hardcoded infrastructure paths and credentials, missing cross-platform support in build configurations, and the need for better error handling and code modularity across the POCs.
| --plugin=protoc-gen-java-grpc=/Users/loite/protoc-gen-grpc-java-1.75.0-osx-aarch_64.exe \ | ||
| --java-grpc_out=../../wrappers/spannerlib-java/src/main/java/ \ | ||
| --java-grpc_opt=paths=source_relative \ | ||
| google/spannerlib/v1/spannerlib.proto | ||
|
|
||
| # dotnet add package Grpc.Tools --version 2.76.0 | ||
| # 4. C# generation | ||
| echo "Generating C#..." | ||
| protoc \ | ||
| --csharp_out=../../wrappers/spannerlib-dotnet/spannerlib-dotnet-grpc-v1/ \ | ||
| --plugin=protoc-gen-csharp_grpc=/Users/loite/.nuget/packages/grpc.tools/2.76.0/tools/macosx_x64/grpc_csharp_plugin \ |
There was a problem hiding this comment.
The script contains hardcoded paths to protoc plugins, which makes it non-portable and specific to a single user's machine (/Users/loite/...). This will cause the script to fail for other developers or in CI/CD environments.
To improve this, consider one of the following approaches:
- Rely on
PATH: Require developers to have theprotoc-gen-*executables in theirPATH. - Use Environment Variables: Allow developers to specify the path to the plugins via environment variables.
- Local Installation: Add a step to download and install the required plugins locally within the project or use a package manager that handles this.
| const projectId = 'span-cloud-testing'; | ||
| const instanceId = 'gargsurbhi-testing'; |
There was a problem hiding this comment.
The projectId and instanceId are hardcoded. This makes the setup script not portable and tightly coupled to a specific GCP project and Spanner instance. It's better to read these values from environment variables to allow other developers to run the tests against their own infrastructure.
For example:
const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing';
const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing';This provides a default but allows for easy overriding.
| const projectId = 'span-cloud-testing'; | |
| const instanceId = 'gargsurbhi-testing'; | |
| const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing'; | |
| const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing'; |
| const projectId = 'span-cloud-testing'; | ||
| const instanceId = 'gargsurbhi-testing'; | ||
| const databaseId = `test-db-koffi-${Math.floor(Math.random() * 1000)}`; |
There was a problem hiding this comment.
There are two issues here:
- The
projectIdandinstanceIdare hardcoded. This makes the setup script not portable. These should be read from environment variables. - The
databaseIdis generated with the prefixtest-db-koffi-. This seems like a copy-paste error from thekoffiPOC. It should betest-db-napi-to be consistent with this N-API POC.
| const projectId = 'span-cloud-testing'; | |
| const instanceId = 'gargsurbhi-testing'; | |
| const databaseId = `test-db-koffi-${Math.floor(Math.random() * 1000)}`; | |
| const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing'; | |
| const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing'; | |
| const databaseId = `test-db-napi-${Math.floor(Math.random() * 1000)}`; |
| const projectId = 'span-cloud-testing'; | ||
| const instanceId = 'gargsurbhi-testing'; |
There was a problem hiding this comment.
The projectId and instanceId are hardcoded. This makes the setup script not portable and tightly coupled to a specific GCP project and Spanner instance. It's better to read these values from environment variables to allow other developers to run the tests against their own infrastructure.
For example:
const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing';
const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing';This provides a default but allows for easy overriding.
| const projectId = 'span-cloud-testing'; | |
| const instanceId = 'gargsurbhi-testing'; | |
| const projectId = process.env.GCP_PROJECT_ID || 'span-cloud-testing'; | |
| const instanceId = process.env.SPANNER_INSTANCE_ID || 'gargsurbhi-testing'; |
| "conditions": [ | ||
| ["OS=='mac'", { | ||
| "libraries": [ | ||
| "<(module_root_dir)/../../../shared/libspanner.so" | ||
| ], | ||
| "xcode_settings": { | ||
| "OTHER_LDFLAGS": [ | ||
| "-Wl,-rpath,<(module_root_dir)/../../../shared" | ||
| ] | ||
| } | ||
| }], | ||
| ["OS=='linux'", { | ||
| "libraries": [ | ||
| "<(module_root_dir)/../../../shared/libspanner.so" | ||
| ], | ||
| "ldflags": [ | ||
| "-Wl,-rpath,'$$ORIGIN/../../../shared'" | ||
| ] | ||
| }] | ||
| ] |
| const path = require('path'); | ||
|
|
||
| // Dynamically locate the actual compiled Go shared library | ||
| const libPath = path.resolve(__dirname, '../../../../../shared/libspanner.so'); |
There was a problem hiding this comment.
The path to the shared library is hardcoded to use the .so extension, which is specific to Linux. This will fail on other operating systems like macOS (.dylib) or Windows (.dll). To make this cross-platform, you should determine the correct extension based on process.platform.
For example:
const getLibraryPath = () => {
const root = path.resolve(__dirname, '../../../../../shared');
switch (process.platform) {
case 'darwin':
return path.join(root, 'libspanner.dylib');
case 'win32':
return path.join(root, 'libspanner.dll');
default:
return path.join(root, 'libspanner.so');
}
};
const libPath = getLibraryPath();| // The SpannerLib service definition is now available through the descriptor | ||
| const SpannerLib = protoDescriptor.google.spannerlib.v1.SpannerLib; | ||
|
|
||
| const client = new SpannerLib('localhost:50051', grpc.credentials.createInsecure()); |
There was a problem hiding this comment.
The gRPC server address is hardcoded to localhost:50051. This limits flexibility. It's better to make this configurable via an environment variable, so the client can connect to a server running on a different host or port.
For example:
const GRPC_SERVER_ADDRESS = process.env.GRPC_SERVER_ADDRESS || 'localhost:50051';
const client = new SpannerLib(GRPC_SERVER_ADDRESS, grpc.credentials.createInsecure());| const client = new SpannerLib('localhost:50051', grpc.credentials.createInsecure()); | |
| const GRPC_SERVER_ADDRESS = process.env.GRPC_SERVER_ADDRESS || 'localhost:50051'; | |
| const client = new SpannerLib(GRPC_SERVER_ADDRESS, grpc.credentials.createInsecure()); |
| let dbName = "dummy-testing-db"; | ||
| try { | ||
| dbName = fs.readFileSync('./test-db.txt', 'utf8').trim(); | ||
| } catch (e) { } |
There was a problem hiding this comment.
The catch block is empty, which swallows any errors that might occur when reading test-db.txt. This can make debugging difficult. It's better to log a message indicating that the file was not found and a default is being used.
For example:
} catch (e) {
console.log('test-db.txt not found, using default. Run `npm run setup` to create a new test database.');
}| } catch (e) { } | |
| } catch (e) { console.log("test-db.txt not found, using default. Run `npm run setup` to create a new test database."); } |
| let dbName = "dummy-testing-db"; | ||
| try { | ||
| dbName = fs.readFileSync('./test-db.txt', 'utf8').trim(); | ||
| } catch (e) { } |
There was a problem hiding this comment.
The catch block is empty, which swallows any errors that might occur when reading test-db.txt. This can make debugging difficult. It's better to log a message indicating that the file was not found and a default is being used.
For example:
} catch (e) {
console.log('test-db.txt not found, using default. Run `npm run setup` to create a new test database.');
}| } catch (e) { } | |
| } catch (e) { console.log("test-db.txt not found, using default. Run `npm run setup` to create a new test database."); } |
952168d to
8654cf9
Compare
No description provided.