Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node: add node cluster mode and standalone examples #2357

Merged
merged 2 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions examples/node/cluster_example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/**
* Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
*/

import {
ClosingError,
ConnectionError,
GlideClusterClient,
InfoOptions,
Logger,
RequestError,
TimeoutError,
} from "@valkey/valkey-glide";

/**
* Creates and returns a GlideClusterClient instance.
* This function initializes a GlideClusterClient with the provided list of nodes.
* The nodesList may contain the address of one or more cluster nodes, and the
* client will automatically discover all nodes in the cluster.
* @param nodesList A list of tuples where each tuple contains a host (str) and port (int). Defaults to [("localhost", 6379)].
* @returns An instance of GlideClusterClient connected to the discovered nodes.
*/
async function createClient(nodesList = [{ host: "localhost", port: 6379 }]) {
const addresses = nodesList.map((node) => ({
host: node.host,
port: node.port,
}));

// Check `GlideClusterClientConfiguration` for additional options.
return await GlideClusterClient.createClient({
addresses: addresses,
// if the server uses TLS, you'll need to enable it. Otherwise the connection attempt will time out silently.
// useTLS: true,
});
}

/**
* Executes the main logic of the application, performing basic operations
* such as SET, GET, PING, and INFO REPLICATION using the provided GlideClusterClient.
* @param client An instance of GlideClusterClient.
*/
async function appLogic(client: GlideClusterClient) {
// Send SET and GET
const setResponse = await client.set("foo", "bar");
Logger.log("info", "app", `Set response is: ${setResponse}`);

const getResponse = await client.get("foo");
Logger.log("info", "app", `Get response is: ${getResponse?.toString()}`);

// Send PING to all primaries (according to Redis's PING request_policy)
ikolomi marked this conversation as resolved.
Show resolved Hide resolved
const pong = await client.ping();
ikolomi marked this conversation as resolved.
Show resolved Hide resolved
Logger.log("info", "app", `PING response: ${pong}`);

// Send INFO REPLICATION to all nodes
const infoReplResps = await client.info({
sections: [InfoOptions.Replication],
adarovadya marked this conversation as resolved.
Show resolved Hide resolved
});
const infoReplicationValues = Object.values(infoReplResps);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Tell why you're getting these values


Logger.log(
"info",
"app",
`INFO REPLICATION responses from all nodes are:\n`,
);

infoReplicationValues.forEach((item) =>
Logger.log("info", "glide", item as string),
);
}

/**
* Executes the application logic with exception handling.
*/
async function execAppLogic() {
// Loop through with exception handling
while (true) {
let client;

try {
client = await createClient();
return await appLogic(client);
} catch (error) {
switch (true) {
case error instanceof ClosingError:
// If the error message contains "NOAUTH", raise the exception
// because it indicates a critical authentication issue.
if ((error as ClosingError).message.includes("NOAUTH")) {
Logger.log(
"error",
"glide",
`Authentication error encountered: ${error}`,
);
} else {
Logger.log(
"warn",
"glide",
`Client has closed and needs to be re-created: ${error}`,
);
}

throw error;
case error instanceof TimeoutError:
// A request timed out. You may choose to retry the execution based on your application's logic
Logger.log("error", "glide", `Timeout error: ${error}`);
throw error;
case error instanceof ConnectionError:
// The client wasn't able to reestablish the connection within the given retries
Logger.log("error", "glide", `Connection error: ${error}`);
throw error;
case error instanceof RequestError:
// Other error reported during a request, such as a server response error
Logger.log(
"error",
"glide",
`RequestError encountered: ${error}`,
);
throw error;
default:
Logger.log("error", "glide", `Unexpected error: ${error}`);
throw error;
}
} finally {
try {
if (client) {
await client.close();
}
} catch (error) {
Logger.log(
"warn",
"glide",
`Error encountered while closing the client: ${error}`,
);
}
}
}
}

function main() {
// In this example, we will utilize the client's logger for all log messages
Logger.setLoggerConfig("info");
// Optional - set the logger to write to a file
// Logger.setLoggerConfig("info", fileName);
execAppLogic();
}

main();
130 changes: 130 additions & 0 deletions examples/node/standalone_example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/**
* Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
*/

import {
ClosingError,
ConnectionError,
GlideClient,
Logger,
RequestError,
TimeoutError,
} from "@valkey/valkey-glide";

/**
* Creates and returns a GlideClient instance.
* This function initializes a GlideClient with the provided list of nodes.
* The nodes_list may contain either only primary node or a mix of primary
* and replica nodes. The GlideClient use these nodes to connect to
* the Standalone setup servers.
* @param nodesList A list of tuples where each tuple contains a host (str) and port (int). Defaults to [("localhost", 6379)].
* @returns An instance of GlideClient connected to the discovered nodes.
*/
async function createClient(nodesList = [{ host: "localhost", port: 6379 }]) {
const addresses = nodesList.map((node) => ({
host: node.host,
port: node.port,
}));

// Check `GlideClientConfiguration` for additional options.
return await GlideClient.createClient({
addresses: addresses,
// if the server uses TLS, you'll need to enable it. Otherwise the connection attempt will time out silently.
// useTLS: true,
});
}

/**
* Executes the main logic of the application, performing basic operations
* such as SET, GET, PING, and INFO REPLICATION using the provided GlideClient.
* @param client An instance of GlideClient.
*/
async function appLogic(client: GlideClient) {
// Send SET and GET
const setResponse = await client.set("foo", "bar");
Logger.log("info", "app", `Set response is: ${setResponse}`);

const getResponse = await client.get("foo");
Logger.log("info", "app", `Get response is: ${getResponse?.toString()}`);

// Send PING to primary
const pong = await client.ping();
Logger.log("info", "app", `PING response: ${pong}`);
}

/**
* Executes the application logic with exception handling.
*/
async function execAppLogic() {
// Loop through with exception handling
while (true) {
let client;

try {
client = await createClient();
return await appLogic(client);
} catch (error) {
switch (true) {
case error instanceof ClosingError:
// If the error message contains "NOAUTH", raise the exception
// because it indicates a critical authentication issue.
if ((error as ClosingError).message.includes("NOAUTH")) {
Logger.log(
"error",
"glide",
`Authentication error encountered: ${error}`,
);
} else {
Logger.log(
"warn",
"glide",
`Client has closed and needs to be re-created: ${error}`,
);
}

throw error;
case error instanceof TimeoutError:
// A request timed out. You may choose to retry the execution based on your application's logic
Logger.log("error", "glide", `Timeout error: ${error}`);
throw error;
case error instanceof ConnectionError:
// The client wasn't able to reestablish the connection within the given retries
Logger.log("error", "glide", `Connection error: ${error}`);
throw error;
case error instanceof RequestError:
// Other error reported during a request, such as a server response error
Logger.log(
"error",
"glide",
`RequestError encountered: ${error}`,
);
throw error;
default:
Logger.log("error", "glide", `Unexpected error: ${error}`);
throw error;
}
} finally {
try {
if (client) {
await client.close();
}
} catch (error) {
Logger.log(
"warn",
"glide",
`Error encountered while closing the client: ${error}`,
);
}
}
}
}

function main() {
// In this example, we will utilize the client's logger for all log messages
Logger.setLoggerConfig("info");
// Optional - set the logger to write to a file
// Logger.setLoggerConfig("info", fileName);
execAppLogic();
}

main();
13 changes: 7 additions & 6 deletions examples/python/cluster_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,13 @@ async def exec_app_logic():
"glide",
f"Authentication error encountered: {e}",
)
raise e
Logger.log(
LogLevel.WARN,
"glide",
f"Client has closed and needs to be re-created: {e}",
)
else:
Logger.log(
LogLevel.WARN,
"glide",
f"Client has closed and needs to be re-created: {e}",
)
raise e
adarovadya marked this conversation as resolved.
Show resolved Hide resolved
except TimeoutError as e:
# A request timed out. You may choose to retry the execution based on your application's logic
Logger.log(LogLevel.ERROR, "glide", f"TimeoutError encountered: {e}")
Expand Down
20 changes: 10 additions & 10 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"devDependencies": {
"@eslint/js": "^9.10.0",
"@types/eslint__js": "^8.42.3",
"@types/eslint-config-prettier": "^6.11.3",
"eslint": "^9.10.0",
"eslint-config-prettier": "^9.1.0",
"prettier": "^3.3.3",
"typescript": "^5.6.2",
"typescript-eslint": "^8.5.0"
}
"devDependencies": {
"@eslint/js": "^9.10.0",
"@types/eslint__js": "^8.42.3",
"@types/eslint-config-prettier": "^6.11.3",
"eslint": "^9.10.0",
"eslint-config-prettier": "^9.1.0",
"prettier": "^3.3.3",
"typescript": "^5.6.2",
"typescript-eslint": "^8.5.0"
}
}
Loading