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

An experimental grpc module graduation #1472

Merged
merged 4 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
8 changes: 5 additions & 3 deletions docs/sources/next/javascript-api/k6-net-grpc/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ weight: 11

# k6/net/grpc

{{< docs/shared source="k6" lookup="grpc-module.md" version="<K6_VERSION>" >}}

The `k6/net/grpc` module provides a [gRPC](https://grpc.io/) client for Remote Procedure Calls (RPC) over HTTP/2.
The `k6/net/grpc` module provides a [gRPC](https://grpc.io/) client for Remote Procedure Calls (RPC) over HTTP/2. It supports unary and streaming (starting [v0.49](https://github.com/grafana/k6/releases/tag/v0.49.0)) RPCs.
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved

| Class/Method | Description |
| --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
Expand All @@ -20,6 +18,10 @@ The `k6/net/grpc` module provides a [gRPC](https://grpc.io/) client for Remote P
| [Params](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/params) | RPC Request specific options. |
| [Response](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/response) | Returned by RPC requests. |
| [Constants](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/constants) | Define constants to distinguish between [gRPC Response](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/response) statuses. |
| [Stream](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream) | Creates a new GRPC stream. |
| [Stream.on(event, handler)](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream/stream-on) | Adds a new listener to one of the possible stream event's. |
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved
| [Stream.write(message)](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream/stream-write) | Writes a message to the stream. |
| [Stream.end()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream/stream-end) | Signals to server that client finished sending. |
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved

## gRPC metrics

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
title: Client
excerpt: 'Client is a gRPC client that can interact with a gRPC server.'
weight: 10
weight: 20
---

# Client

{{< docs/shared source="k6" lookup="grpc-module.md" version="<K6_VERSION>" >}}

`Client` is a gRPC client that can interact with a gRPC server. Only unary RPCs are currently supported in this module.
`Client` is a gRPC client that can interact with a gRPC server.

| Method | Description |
| ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
Expand Down
204 changes: 204 additions & 0 deletions docs/sources/next/javascript-api/k6-net-grpc/stream/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
---
title: Stream
excerpt: 'GRPC Streams'
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved
weight: 30
---

# Stream

Using a GRPC client creates a stream. An important note that the client should be already connected (client.connect called) to the server before creating a stream.
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved

| Method | Description |
| ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| [Stream(client, url, [,params])](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream) | Using a GRPC client creates a stream. |
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved
| [Stream.write(message)](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream/stream-write) | Writes a message to the stream. |
| [Stream.on(event, handler)](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream/stream-on) | Set up handler functions for various events on the GRPC stream. |
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved
| [Stream.end()](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream/stream-end) | Signals to the server that the client has finished sending. |

### Examples

_A k6 script that sends several randomly chosen points from the pre-generated feature database with a variable delay in between. Prints the statistics when they are sent from the server._

{{< code >}}

```javascript
import { Client, Stream } from 'k6/net/grpc';
import { sleep } from 'k6';

const COORD_FACTOR = 1e7;

const GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';
const GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../../grpc_server/route_guide.proto';

const client = new Client();
client.load([], GRPC_PROTO_PATH);

// a sample DB of points
const DB = [
{
location: { latitude: 407838351, longitude: -746143763 },
name: 'Patriots Path, Mendham, NJ 07945, USA',
},
{
location: { latitude: 408122808, longitude: -743999179 },
name: '101 New Jersey 10, Whippany, NJ 07981, USA',
},
{
location: { latitude: 413628156, longitude: -749015468 },
name: 'U.S. 6, Shohola, PA 18458, USA',
},
{
location: { latitude: 419999544, longitude: -740371136 },
name: '5 Conners Road, Kingston, NY 12401, USA',
},
{
location: { latitude: 414008389, longitude: -743951297 },
name: 'Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA',
},
{
location: { latitude: 419611318, longitude: -746524769 },
name: '287 Flugertown Road, Livingston Manor, NY 12758, USA',
},
{
location: { latitude: 406109563, longitude: -742186778 },
name: '4001 Tremley Point Road, Linden, NJ 07036, USA',
},
{
location: { latitude: 416802456, longitude: -742370183 },
name: '352 South Mountain Road, Wallkill, NY 12589, USA',
},
{
location: { latitude: 412950425, longitude: -741077389 },
name: 'Bailey Turn Road, Harriman, NY 10926, USA',
},
{
location: { latitude: 412144655, longitude: -743949739 },
name: '193-199 Wawayanda Road, Hewitt, NJ 07421, USA',
},
];

export default () => {
if (__ITER == 0) {
client.connect(GRPC_ADDR, { plaintext: true });
}

const stream = new Stream(client, 'main.RouteGuide/RecordRoute');

stream.on('data', (stats) => {
console.log('Finished trip with', stats.pointCount, 'points');
console.log('Passed', stats.featureCount, 'features');
console.log('Travelled', stats.distance, 'meters');
console.log('It took', stats.elapsedTime, 'seconds');
});

stream.on('error', (err) => {
console.log('Stream Error: ' + JSON.stringify(err));
});

stream.on('end', () => {
client.close();
console.log('All done');
});

// send 5 random items
for (let i = 0; i < 5; i++) {
const point = DB[Math.floor(Math.random() * DB.length)];
pointSender(stream, point);
}

// close the client stream
stream.end();

sleep(1);
};

const pointSender = (stream, point) => {
console.log(
'Visiting point ' +
point.name +
' ' +
point.location.latitude / COORD_FACTOR +
', ' +
point.location.longitude / COORD_FACTOR
);

// send the location to the server
stream.write(point.location);

sleep(0.5);
};
```

{{< /code >}}

_A k6 script that sends a rectangle message and results (features) are streamed back to the client._

{{< code >}}

```javascript
import { Client, Stream } from 'k6/net/grpc';
import { sleep } from 'k6';

const COORD_FACTOR = 1e7;

const GRPC_ADDR = __ENV.GRPC_ADDR || '127.0.0.1:10000';
const GRPC_PROTO_PATH = __ENV.GRPC_PROTO_PATH || '../../grpc_server/route_guide.proto';

const client = new Client();

client.load([], GRPC_PROTO_PATH);

export default () => {
client.connect(GRPC_ADDR, { plaintext: true });

const stream = new Stream(client, 'main.FeatureExplorer/ListFeatures', null);

stream.on('data', function (feature) {
console.log(
'Found feature called "' +
feature.name +
'" at ' +
feature.location.latitude / COORD_FACTOR +
', ' +
feature.location.longitude / COORD_FACTOR
);
});

stream.on('end', function () {
// The server has finished sending
client.close();
console.log('All done');
});

stream.on('error', function (e) {
// An error has occurred and the stream has been closed.
console.log('Error: ' + JSON.stringify(e));
});

// send a message to the server
stream.write({
lo: {
latitude: 400000000,
longitude: -750000000,
},
hi: {
latitude: 420000000,
longitude: -730000000,
},
});

sleep(0.5);
};
```

{{< /code >}}

The preceding examples use a demo server, which you can run with the following command (Golang should be installed) in [k6 repository's root](https://github.com/grafana/k6):

{{< code >}}

```bash
$ go run -mod=mod examples/grpc_server/*.go
```

{{< /code >}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
title: 'Stream.end()'
excerpt: 'Signals to the server that the client has finished sending.'
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved
weight: 40
---

# Stream.end()

Signals to the server that the client has finished sending messages.

### Example

<div class="code-group" data-props='{"labels": ["Simple example"], "lineNumbers": [true]}'>

```javascript
import { Client, Stream } from 'k6/net/grpc';
import { sleep } from 'k6';

const COORD_FACTOR = 1e7;

const client = new Client();
client.load([], '../../grpc_server/route_guide.proto');

export default () => {
if (__ITER == 0) {
client.connect('127.0.0.1:10000', { plaintext: true });
}

const stream = new Stream(client, 'main.RouteGuide/RecordRoute');

stream.on('data', (stats) => {
console.log('Finished trip with', stats.pointCount, 'points');
console.log('Passed', stats.featureCount, 'features');
console.log('Traveled', stats.distance, 'meters');
console.log('It took', stats.elapsedTime, 'seconds');
});

// send 2 items
stream.write({ latitude: 406109563, longitude: -742186778 });
stream.write({ latitude: 416802456, longitude: -742370183 });

// send end-signal to the server
stream.end();

sleep(1);
};
```

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: 'Error'
head_title: 'gRPC.Error'
excerpt: 'The error object of a gRPC stream.'
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved
weight: 15
---

# Error

The error object is the object that is passed to the `error` event handler function.

| Name | Type | Description |
| --------------- | ------ | ------------------------------------- |
| `Error.code` | number | A gRPC error code. |
| `Error.details` | array | A list details attached to the error. |
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved
| `Error.message` | string | An original error message. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: 'Stream.on()'
excerpt: 'Set up handler functions for various events on the GRPC stream.'
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved
weight: 10
---

# Stream.on()

Set up handler functions for various events on the GRPC stream.
olegbespalov marked this conversation as resolved.
Show resolved Hide resolved

| Parameter | Type | Description |
| --------- | -------- | -------------------------------------------- |
| event | string | The event name to define a handler for. |
| handler | function | The function to call when the event happens. |

Possible events:

| Event name | Description |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| data | Emitted when the server sends data. |
| error | Emitted when an error occurs. In case of the error, an [`Error`](https://grafana.com/docs/k6/<K6_VERSION>/javascript-api/k6-net-grpc/stream/stream-error) object sends to the handler function. |
| end | Emitted when the server closes the incoming stream. |

### Example

<div class="code-group" data-props='{"labels": ["Simple example"], "lineNumbers": [true]}'>

```javascript
import { Client, Stream } from 'k6/net/grpc';
import { sleep } from 'k6';

const COORD_FACTOR = 1e7;

const client = new Client();
client.load([], '../../grpc_server/route_guide.proto');

export default () => {
if (__ITER == 0) {
client.connect('127.0.0.1:10000', { plaintext: true });
}

const stream = new Stream(client, 'main.RouteGuide/RecordRoute');

// sets up a handler for the data (server sends data) event
stream.on('data', (stats) => {
console.log('Finished trip with', stats.pointCount, 'points');
console.log('Passed', stats.featureCount, 'features');
console.log('Traveled', stats.distance, 'meters');
console.log('It took', stats.elapsedTime, 'seconds');
});

// sets up a handler for the end event (stream closes)
stream.on('end', function () {
// The server has finished sending
client.close();
console.log('All done');
});

// sets up a handler for the error event (an error occurs)
stream.on('error', function (e) {
// An error has occurred and the stream has been closed.
console.log('Error: ' + JSON.stringify(e));
});

sleep(1);
};
```

</div>
Loading