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

Microservice support #640

Merged
merged 97 commits into from
Jun 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
8c12a57
WIP: A skeleton microservice object
Mar 1, 2023
8721da1
Responds to a PING
Mar 3, 2023
a07aa71
Clarified - this is NOT a JS thing!
Mar 3, 2023
3d4cf0d
Renamed the example microservice
levb Mar 5, 2023
624b542
First implementation of the default endpoint
levb Mar 7, 2023
1961a5f
Sequence calculator service - a working example of multiple endpoints.
levb Mar 10, 2023
a443b1e
Added support for info, stats, natsError
levb Mar 20, 2023
dcfdbea
refactored with the 'micro' prefix
levb Mar 27, 2023
57d181c
fixed includes
levb Mar 27, 2023
3af0846
wip custom error handler
levb Mar 27, 2023
3f017b8
Merge branch 'lev-microservice-proto' of github.com:nats-io/nats.c in…
levb Apr 16, 2023
63ede6a
simplified examples
levb Apr 17, 2023
8e27ede
Fixed leaks, debugged the tests
levb Apr 17, 2023
39cc6b2
Groups
levb Apr 18, 2023
dde5993
"Basic" test.
levb Apr 25, 2023
0f5b888
more tests from go, fixes
levb Apr 26, 2023
95388fb
Docs (sans HTML) and some PR feedback (names)
levb May 4, 2023
06ffeac
request handler returns err instead of calling Respond(Error)
levb May 8, 2023
9d7a543
Reworked how endpoints are stores in servbice, refcounting
levb May 11, 2023
74c70c7
fixed copyright messages
levb May 12, 2023
3b9157f
PR feedback: fixes in examples
levb May 12, 2023
3f8321d
PR feedback: removed redundant include mem.h
levb May 12, 2023
af31cd9
PR Feedback: use `size_t` and `natsSubscription_GetSubject`
levb May 12, 2023
373d5dd
PR feedback: initialize decoded_len
levb May 12, 2023
84dffc2
PR feedback: removed err->message silliness
levb May 12, 2023
cd5fae8
PR feedback: cast size_t to int calling natsMsg_Create
levb May 12, 2023
a346df6
Ref counting fixes
levb May 15, 2023
9996515
PR feedback: strdup-ed strings in Info and Stats
levb May 16, 2023
1aecdd4
Fixed NULL pointer crashes in the previous commit
levb May 16, 2023
e071af1
PR feedback: micro_new_endpoint: check if endpoint config is NULL
levb May 16, 2023
9968033
PR feedback: missing unlocks
levb May 16, 2023
0b1acae
PR feedback: use natsBuf_AppendByte where appropriate
levb May 16, 2023
d3816fc
PR feedback: CamelCased remaining public fields
levb May 16, 2023
4745e19
Added support for multiple handlers for ConnectionClosed and AsyncErr…
levb May 19, 2023
2048d4c
added is_internal to microError to avoid freeing internal values
levb May 21, 2023
44a4652
PR feedback: initialize to avoid a warning
levb May 21, 2023
843fd8a
Removed the never-implemented schema
levb May 22, 2023
d6f3747
Merge pull request #657 from nats-io/lev-microservice-proto-noschema
levb May 22, 2023
11375c7
Merge branch 'lev-microservice-proto' of github.com:nats-io/nats.c in…
levb May 22, 2023
cc1881c
PR feedback: added a missing FREE(replaced)
levb May 22, 2023
dfcdf2d
PR feedback: free the replaced value in SetErrorHandler and SetClosedCB
levb May 22, 2023
3b13ac0
reversed: previous (free the replaced value...), added a test
levb May 22, 2023
ff454ba
PR feedback: whitespace
levb May 22, 2023
59c3c4e
PR feedback: nit - added natsOptions_(un)lock
levb May 22, 2023
8f169d0
PR feedback: hopefully fixes all windows warnings
levb May 22, 2023
3877534
PR feedback: hopefully fixes all windows warnings
levb May 22, 2023
2b45835
PR feedback: removed previous PR, wrong branch
levb May 22, 2023
2497763
restored LOCK_OPTIONS macros
levb May 22, 2023
a44bf1f
Merge pull request #656 from nats-io/lev-microservice-proto-cblist
levb May 22, 2023
a0dafe8
`Done` handler
levb May 22, 2023
58616c4
Merge branch 'lev-microservice-proto' of github.com:nats-io/nats.c in…
levb May 23, 2023
9182317
printf
levb May 23, 2023
ee020b7
Added Test_MicroAsyncErrorHandler
levb May 23, 2023
59c5de8
PR feedback: warnings
levb May 23, 2023
36cb481
Fixed AsyncErr test
levb May 23, 2023
964d210
Now with a Done handler to fix the test on gcc builds
levb May 23, 2023
c3677d2
try-1
levb May 23, 2023
b3ee831
wip
levb May 29, 2023
7d732fb
wip
levb May 29, 2023
de0f8a8
wip2
levb May 29, 2023
e531f28
wip3
levb May 29, 2023
0e85175
wip4
levb May 29, 2023
e4b80fd
wip5
levb May 30, 2023
71bb342
reworked wip
levb May 31, 2023
c38ed27
reworked wip2
levb Jun 1, 2023
3d0d3ab
reworked wip3
levb Jun 1, 2023
cb68bad
reworked wip4
levb Jun 1, 2023
a4d89bc
reworked wip5
levb Jun 1, 2023
8f87ea2
reworked wip5
levb Jun 1, 2023
3ca86b6
reworked wip6
levb Jun 2, 2023
5dab55d
Merge branch 'main' into lev-tmp2
levb Jun 2, 2023
52c4881
reworked wip7
levb Jun 3, 2023
2019f51
reworked wip8
levb Jun 3, 2023
f76a3c5
reworked wip9
levb Jun 3, 2023
f91919f
Merge branch 'main' of github.com:nats-io/nats.c into lev-microservic…
levb Jun 3, 2023
863af3e
Merge branch 'lev-microservice-proto' into lev-tmp2
levb Jun 3, 2023
104a46c
reworked wip10
levb Jun 3, 2023
b80dc96
reworked wip11
levb Jun 3, 2023
5ae5e6f
reworked wip12
levb Jun 3, 2023
e2d41f0
reworked wip13
levb Jun 3, 2023
f1f1191
reworked wip14
levb Jun 4, 2023
8d66c11
reworked wip15
levb Jun 4, 2023
9da1b56
wip nits
levb Jun 4, 2023
10fe2c5
wip more nits
levb Jun 4, 2023
ef143d3
Merge branch 'dev' of github.com:nats-io/nats.c into lev-microservice…
levb Jun 5, 2023
b01f694
Merge branch 'lev-microservice-proto' of github.com:nats-io/nats.c in…
levb Jun 5, 2023
f255707
Moving global variables inside natsLib for proper cleanup on close
kozlovic Jun 5, 2023
4e0709d
PR feedback sans global elimination
levb Jun 6, 2023
2474610
Merge branch 'lev-tmp2' of github.com:nats-io/nats.c into lev-tmp2
levb Jun 6, 2023
394e4b2
Restored num_services=5 in tests
levb Jun 6, 2023
fd95b7b
PR feedback: microError.message
levb Jun 7, 2023
e92657b
PR feedback: nats_vsnprintf
levb Jun 7, 2023
338951d
PR feedback: nats_vsnprintf, #2
levb Jun 7, 2023
a268db3
Merge pull request #660 from nats-io/lev-tmp2
levb Jun 10, 2023
eaa4925
[CHANGED] More verbose endpoint INFO (#663)
levb Jun 13, 2023
9016f15
PR feedback: unsed var
levb Jun 13, 2023
accace4
Fix to run on Windows
kozlovic Jun 13, 2023
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
3 changes: 2 additions & 1 deletion examples/examples.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2015-2018 The NATS Authors
// Copyright 2015-2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
Expand All @@ -15,6 +15,7 @@
#define EXAMPLES_H_

#include <nats.h>
#include <micro_args.h>
levb marked this conversation as resolved.
Show resolved Hide resolved
#include <stdio.h>
#include <string.h>

Expand Down
147 changes: 147 additions & 0 deletions examples/micro-arithmetics.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
// Copyright 2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "examples.h"

// Sequence NATS microservice example.
//
// This example illustrates multiple NATS microservices communicating with each
// other. Please see the main microservice, micro-sequence.c for a more detailed
// explanation.
//
// This specific microservice implements add, multiply, and divide operations.

// arithmeticsOp is a type for a C function that implements am operation: add,
// multiply, divide.
typedef void (*arithmeticsOP)(long double *result, long double a1, long double a2);

// handle_arithmetics_op is a helper function that wraps an implementation of an
// operation into a request handler.
static microError *
handle_arithmetics_op(microRequest *req, arithmeticsOP op)
{
microError *err = NULL;
microArgs *args = NULL;
long double a1, a2, result;
char buf[1024];
int len = 0;

err = micro_ParseArgs(&args, microRequest_GetData(req), microRequest_GetDataLength(req));
if ((err == NULL) && (microArgs_Count(args) != 2))
{
err = micro_Errorf("invalid number of arguments, expected 2 got %d", microArgs_Count(args));
}
if (err == NULL)
err = microArgs_GetFloat(&a1, args, 0);
if (err == NULL)
err = microArgs_GetFloat(&a2, args, 1);
if (err == NULL)
op(&result, a1, a2);
if (err == NULL)
len = snprintf(buf, sizeof(buf), "%Lf", result);
if (err == NULL)
err = microRequest_Respond(req, buf, len);

microArgs_Destroy(args);
return microError_Wrapf(err, "failed to handle arithmetics operation");
}

static void add(long double *result, long double a1, long double a2)
{
*result = a1 + a2;
}

static void divide(long double *result, long double a1, long double a2)
{
*result = a1 / a2;
}

static void multiply(long double *result, long double a1, long double a2)
{
*result = a1 * a2;
}

// request handlers for each operation.
static microError *handle_add(microRequest *req) { return handle_arithmetics_op(req, add); }
static microError *handle_divide(microRequest *req) { return handle_arithmetics_op(req, divide); }
static microError *handle_multiply(microRequest *req) { return handle_arithmetics_op(req, multiply); }

// main is the main entry point for the microservice.
int main(int argc, char **argv)
{
natsStatus s = NATS_OK;
microError *err = NULL;
natsConnection *conn = NULL;
natsOptions *opts = NULL;
microService *m = NULL;
microGroup *g = NULL;
char errorbuf[1024];

microServiceConfig cfg = {
.Description = "Arithmetic operations - NATS microservice example in C",
.Name = "c-arithmetics",
.Version = "1.0.0",
};
microEndpointConfig add_cfg = {
.Name = "add",
.Handler = handle_add,
};
microEndpointConfig divide_cfg = {
.Name = "divide",
.Handler = handle_divide,
};
microEndpointConfig multiply_cfg = {
.Name = "multiply",
.Handler = handle_multiply,
};

// Connect to NATS server
opts = parseArgs(argc, argv, "");
s = natsConnection_Connect(&conn, opts);
if (s != NATS_OK)
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
natsOptions_Destroy(opts);
return 1;
}

// Create the Microservice that listens on nc.
err = micro_AddService(&m, conn, &cfg);

// Add the endpoints for the functions.
if (err == NULL)
microService_AddGroup(&g, m, "op");
if (err == NULL)
err = microGroup_AddEndpoint(g, &add_cfg);
if (err == NULL)
err = microGroup_AddEndpoint(g, &multiply_cfg);
if (err == NULL)
err = microGroup_AddEndpoint(g, &divide_cfg);

// Run the service, until stopped.
if (err == NULL)
err = microService_Run(m);

// Cleanup.
microService_Destroy(m);
levb marked this conversation as resolved.
Show resolved Hide resolved
natsOptions_Destroy(opts);
natsConnection_Destroy(conn);
if (err != NULL)
{
printf("Error: %s\n", microError_String(err, errorbuf, sizeof(errorbuf)));
microError_Destroy(err);
return 1;
}
return 0;
}
229 changes: 229 additions & 0 deletions examples/micro-func.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
// Copyright 2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "examples.h"

// Sequence NATS microservice example.
//
// This example illustrates multiple NATS microservices communicating with each
// other. Please see the main microservice, micro-sequence.c for a more detailed
// explanation.
//
// This specific microservice implements factorial, fibonacci, and power2
// functions. Instead of performing arithmetic operations locally, we call the
// arithmetics microservice to perform the operations.

// functionHandler is a type for a C function that implements a "function", i.e.
// power2, factorial, etc.
typedef microError *(*functionHandler)(long double *result, natsConnection *conn, int n);

// callArithmetics is a helper function that calls the arithmetics microservice.
static microError *
call_arithmetics(long double *result, natsConnection *nc, const char *subject, long double a1, long double a2)
{
microError *err = NULL;
microClient *client = NULL;
natsMsg *response = NULL;
microArgs *args = NULL;
char buf[1024];
int len;

err = micro_NewClient(&client, nc, NULL);
if (err == NULL)
len = snprintf(buf, sizeof(buf), "%Lf %Lf", a1, a2);
if (err == NULL)
err = microClient_DoRequest(&response, client, subject, buf, len);
if (err == NULL)
err = micro_ParseArgs(&args, natsMsg_GetData(response), natsMsg_GetDataLength(response));
if (err == NULL)
err = microArgs_GetFloat(result, args, 0);

microClient_Destroy(client);
natsMsg_Destroy(response);
return err;
}

// factorial implements the factorial(N) function. Calls the arithmetics service
// for all multiplications.
static microError *
factorial(long double *result, natsConnection *nc, int n)
{
microError *err = NULL;
int i;

if (n < 1)
return micro_Errorf("n=%d. must be greater than 0", n);

*result = 1;
for (i = 1; i <= n; i++)
{
err = call_arithmetics(result, nc, "op.multiply", *result, i);
if (err != NULL)
return err;
}
return NULL;
}

// fibonacci implements the fibonacci(N) function. Calls the arithmetics service
// for all additions.
static microError *
fibonacci(long double *result, natsConnection *nc, int n)
{
microError *err = NULL;
int i;
long double n1, n2;

if (n < 0)
return micro_Errorf("n=%d. must be non-negative", n);

if (n < 2)
{
*result = n;
return NULL;
}

for (i = 1, n1 = 0, n2 = 1; i <= n; i++)
{
err = call_arithmetics(result, nc, "op.add", n1, n2);
if (err != NULL)
return err;
n1 = n2;
n2 = *result;
}
return NULL;
}

// power2 implements the 2**N function. Calls the arithmetics service
// for all multiplications.
static microError *power2(long double *result, natsConnection *nc, int n)
{
microError *err = NULL;
int i;

if (n < 1)
return micro_Errorf("n=%d. must be greater than 0", n);

*result = 1;
for (i = 1; i <= n; i++)
{
err = call_arithmetics(result, nc, "op.multiply", *result, 2);
if (err != NULL)
return err;
}
return NULL;
}

// handle_function_op is a helper function that wraps an implementation function
// like factorial, fibonacci, etc. into a request handler.
static microError *
handle_function_op(microRequest *req, functionHandler op)
{
microError *err = NULL;
microArgs *args = NULL;
int n;
long double result;
char buf[1024];
int len = 0;

err = micro_ParseArgs(&args, microRequest_GetData(req), microRequest_GetDataLength(req));
if ((err == NULL) && (microArgs_Count(args) != 1))
{
err = micro_Errorf("Invalid number of arguments, expected 1 got %d", microArgs_Count(args));
}
if (err == NULL)
err = microArgs_GetInt(&n, args, 0);
if (err == NULL)
err = op(&result, microRequest_GetConnection(req), n);
if (err == NULL)
len = snprintf(buf, sizeof(buf), "%Lf", result);
if (err == NULL)
err = microRequest_Respond(req, buf, len);

microArgs_Destroy(args);
return err;
}

// handle_... are the request handlers for each function.
static microError *handle_factorial(microRequest *req) { return handle_function_op(req, factorial); }
static microError *handle_fibonacci(microRequest *req) { return handle_function_op(req, fibonacci); }
static microError *handle_power2(microRequest *req) { return handle_function_op(req, power2); }

// main is the main entry point for the microservice.
int main(int argc, char **argv)
{
natsStatus s = NATS_OK;
microError *err = NULL;
natsOptions *opts = NULL;
natsConnection *conn = NULL;
microService *m = NULL;
microGroup *g = NULL;
char errorbuf[1024];

microServiceConfig cfg = {
.Description = "Functions - NATS microservice example in C",
.Name = "c-functions",
.Version = "1.0.0",
};
microEndpointConfig factorial_cfg = {
.Name = "factorial",
.Handler = handle_factorial,
};
microEndpointConfig fibonacci_cfg = {
.Name = "fibonacci",
.Handler = handle_fibonacci,
};
microEndpointConfig power2_cfg = {
.Name = "power2",
.Handler = handle_power2,
};

// Connect to NATS server
opts = parseArgs(argc, argv, "");
s = natsConnection_Connect(&conn, opts);
if (s != NATS_OK)
{
printf("Error: %u - %s\n", s, natsStatus_GetText(s));
nats_PrintLastErrorStack(stderr);
natsOptions_Destroy(opts);
return 1;
}

// Create the Microservice that listens on nc.
err = micro_AddService(&m, conn, &cfg);

// Add the endpoints for the functions.
if (err == NULL)
err = microService_AddGroup(&g, m, "f");
if (err == NULL)
err = microGroup_AddEndpoint(g, &factorial_cfg);
if (err == NULL)
err = microGroup_AddEndpoint(g, &fibonacci_cfg);
if (err == NULL)
err = microGroup_AddEndpoint(g, &power2_cfg);

// Run the service, until stopped.
if (err == NULL)
err = microService_Run(m);

// Cleanup.
microService_Destroy(m);
levb marked this conversation as resolved.
Show resolved Hide resolved
natsOptions_Destroy(opts);
natsConnection_Destroy(conn);
if (err != NULL)
{
printf("Error: %s\n", microError_String(err, errorbuf, sizeof(errorbuf)));
microError_Destroy(err);
return 1;
}
return 0;
}
Loading