GithubHelp home page GithubHelp logo

xk6-grpc's Introduction

xk6-grpc

Warning

Starting k6 version v0.49 the code of the k6/x/grpc extension is part of the k6/net/grpc of the main k6 repository. Please contribute and open issues there. This repository is no longer maintained.

This extension is re-designing of the k6's GRPC module that also should bring new features like GRPC streaming (it's available in the k6 as k6/experimental/grpc).

The extension code copied from the original k6's GRPC module. The module documentation is available here.

The new stream's functionality (more examples you can find in the examples folder):

import { Stream } from 'k6/x/grpc'

// Stream(client, method)
// - client - already initialized and connected client with the loaded definitions
// - method - a gRPC method URL to invoke.
const stream = new Stream(
  client,
  'foo.BarService/sayHello'
)

// A `stream.on` method adds a new handler for different kind of the events.
// 
// Currently supported: 
// `data`  - triggered when the server send data to the stream
// `error` - an error occurs
// `end`   - triggered when the server has finished sending the data
// You could register multiple handlers for the same kind event.
stream.on('data', message => {
  // server send data, processing...
})

// Write data to the stream
stream.write({ message: 'foo' })

// Signals the server that the client has finished sending the data
stream.end()

Requirements

  • Golang 1.19+g
  • Git
  • xk6 (go install go.k6.io/xk6/cmd/xk6@latest)
  • curl (downloading the k6 core's linter rule-set)

Getting started

  1. Build the k6's binary with the module:
$ make build
  1. Run the GRPC demo server in a separated terminal:
$ make grpc-server-run
  1. Run the example:
$ ./k6 run examples/grpc_client_streaming.js

Contributing

Contributing to this repository is following general k6's contribution guidelines since the long-term goal is to merge this extension into the main k6 repository.

However, since right now there are two modules, k6/net/grpc and k6/experimental/grpc, that have similar functionality (the experimental module started as a copy), and not sharing the code, there is a specialty exists that forces us to backport (or forward port) changes to shared functionality (e.g., bug fixes) between modules.

We don't expect every contributor to do that and are happy to do that for you, but if you want to do that by yourself, you can do that.

Testing

To run the test you can use the make test target.

Linting

To run the linter you can use the make lint target.

Important

By default there is golangci-lint config presented. Since the long-term goal is to merge the module back to the grafana/k6 we use the k6's linter rules. The rule set will be downloaded automatically while the first run of the make lint or you could do that manually by running make linter-config.

xk6-grpc's People

Contributors

chrismoran-mica avatar codebien avatar olegbespalov avatar thiagodpf avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xk6-grpc's Issues

Running tests require running `go mod vendor`

This repo does not vendor its dependencies, as this doesn't really work with xk6.

But the test are using files in vendor directory and the CI does actually run go mod vendor before actually running the tests - which is why it works there.

But locally running the tests will fail until you run go mod vendor.

Not certain whether we should vendor the dependencies as a stop gap solution or figure out to a way to get the proto files in some other way.

Migrate to the GRPC's reflection v1

What?

GRPC's reflection v1alfa is deprecated, so we have to migrate to v1 from v1alpha once it is possible (grpc/grpc-go#5684)

Also, revert the exclude rules from 775d7dd

Why?

That way, we keep the code stable.

Tasks

Prevent send on stream if closed

I've been trying this new extension quite extensively for a few days now, mainly to test a GRPC streaming API, and everything has been quite smooth, thanks for the great work!

I've been struggling a bit on an issue that I'm not sure what's the proper way to address.
When doing bidirectional streaming RPC, where the client starts streaming requests to the server, and the server streams replies.

Is there any way to prevent such errors when the server send a final reply and close the stream before the client has send all its data (because processing is done and the additional data the client might send is irrelevant):

ERRO[0105] failed to send data to the stream error=EOF
INFO[0105] Stream Error: {"code":2,"details":[],"message":"EOF"} source=console

Is there a way to prevent a send if the stream is closed? Or to properly handle that error?

GRPC Stream Metrics

What?

Come up with & implement GRPC streaming metrics.

Why?

Metrics are essential for performance testing.

GRPC Stream Parameterization

What?

Implement params in Stream constructor.

It should be the same way as we parameterize the Invoke.

Why?

It's essential to have this.

Expose the stream events' const

What?

We have to expose the Stream events' constants to make this accessible with the TypeScript.

We have something similar with the GRPC statuses https://github.com/grafana/xk6-grpc/blob/main/grpc/grpc.go#L66-L89

The constants should be available in the grpc.StreamEvent (e.g. grpc.StreamEvent.Data). That way, the existing k6-DefinitelyTyped will work.

The other way of fixing the issue is grafana/k6-DefinitelyTyped#13

Why?

The current k6-DefinitelyTyped code isn't working.

GRPC Reflect call in client.connect cannot include user-provided headers

Feature Description

Some GRPC servers require a header to authenticate any call (including reflection). The invoke command covers this use case, but the reflect command that's bundled in the connect command does not, which leads to authentication errors.

Suggested Solution (optional)

Add another parameter in the connect function to add metadata to the reflect command

Already existing or connected issues / PRs (optional)

I have a PR that implements this, but I'm unable to sign the CLA.
grafana/k6#3242

prematurely "context canceled" on gRPC stream when timeout is set

Brief summary

Hello again folks!

I'm using the experimental module k6/experimental/grpc to perform load tests on a service that communicates using bidirectional gRPC stream.

When creating the stream from the gRPC client (based on this example), I am passing the timeout parameter and this is causing the problem of the "context being canceled prematurely" (in golang) when I close the sending stream (client side).

k6 version

v0.45.0

OS

Ubuntu 20.04.6 LTS

Docker version and image (if applicable)

No response

Steps to reproduce the problem

See the script snippet below, notice that after sending all items to the server, I am closing the (client) sending stream (but the receiving stream must remain open until the server closes it OR the timeout is reached):

  // notice the timeout at the end of the line ------------------------------vvvv
  const stream = new Stream(grpcClient, 'grp.Service/MyEndpoint', { timeout: '2m' });

  // register the response listener...
  stream.on('data', (response) => {
    doSomeChecks(response);
  });

  // send some items to the server...
  for (let i = 0; i < 5; i++) {
    stream.write(item);
  }

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

What happens in practice is that after closing the stream (.end()) on the client side, due to the configured timeout (in the script), the code that runs behind the scenes (in Golang) is canceling the context used by the whole stream (before the timeout has been reached!!!). However, when doing so, the receiving stream is also canceled and the server does not have time to send its responses.

When the sending stream is closed (in the script ๐Ÿ‘†), the Golang code behind the scenes goes through here ๐Ÿ‘‡:
https://github.com/grafana/k6/blob/703970eb58d756451c073d0797dce36e067bc386/vendor/github.com/grafana/xk6-grpc/grpc/stream.go#L222-L233
note that on line 228 ๐Ÿ‘† a function is queued and it will call the function s.closeWithError(err) (line 229)...

...and looking inside the closeWithError function ๐Ÿ‘‡, we can see that if there is a timeout defined (line 336), it will be canceled prematurely:
https://github.com/grafana/k6/blob/703970eb58d756451c073d0797dce36e067bc386/vendor/github.com/grafana/xk6-grpc/grpc/stream.go#L325-L338

Unfortunately I don't know how to suggest a fix, as I lack knowledge of the logic you guys used behind this bidirectional control mechanism. But I think it's worth registering this issue.

The workaround I currently have is to not set the timeout on stream creation (in the script). Unfortunately, if the server takes too long to complete the response (e.g. in a stress test measuring throughput), this results in a VU stuck in one iteration until it reaches the scenario's gracefulStop. ๐Ÿ˜ž

Expected behaviour

It is expected that when closing the stream on the client side, if there is a timeout defined and no errors are passed to the closeWithError(err) function, then the context should not be canceled prematurely.
At least that's how I see the solution to the problem.

Actual behaviour

The context is being cancelled, regardless of whether there is an error or not (as a function parameter: closeWithError(err))

Workflows Test

This is just a mock issue in order to test repo's workflows.

Support binary GRPC metadata

What?

We have to back-port the grafana/k6#3234 to xk6-grpc.

The important part is that this binary metadata support should be also implemented for the Stream's metadata and for Reflections's metadata (grafana/k6#3241). So it's probably worth abstracting parsing logic and re-using it in all places.

Why?

The xk6-grpc is considered as the future version of the k6's grpc module it should have all functionality that has the legacy k6/net/grpc module.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.