Nice-GRPC Client Deadline Middleware

2.0.18 · active · verified Tue Apr 21

The `nice-grpc-client-middleware-deadline` package provides client-side middleware for the `nice-grpc` library, enabling developers to easily set and enforce deadlines for outgoing gRPC calls. When a configured deadline is exceeded, the in-flight gRPC call is automatically cancelled, and the client receives a `ClientError` with the `DEADLINE_EXCEEDED` status code. This functionality is crucial for building resilient microservices by preventing requests from running indefinitely, which could otherwise lead to resource exhaustion and cascading failures. The package is currently at version 2.0.18, with a sustainable maintenance record and consistent updates aligning with the `nice-grpc` ecosystem's focus on modern TypeScript, Promises, and Async Iterables. It is a key component in `nice-grpc`'s modular approach to client-side concerns, offering a clear differentiator in its modern API design compared to more traditional gRPC implementations.

Common errors

Warnings

Install

Imports

Quickstart

This example demonstrates how to integrate `createDeadlineClientMiddleware` with a `nice-grpc` client. It shows how to apply the middleware to a client factory, create a client, and then make RPC calls with both per-call and factory-wide default deadlines using the `deadline` option.

import { createChannel, createClientFactory, createClient, ClientError, status } from 'nice-grpc';
import { createDeadlineClientMiddleware } from 'nice-grpc-client-middleware-deadline';
import { ProtoGrpcType } from './greeter'; // Assuming you have compiled protobufs
import { GreeterClient, GreeterDefinition } from './greeter/Greeter'; // Adjust based on your proto compilation

interface HelloRequest {
  name: string;
}

interface HelloResponse {
  message: string;
}

// Mock Service Definition (replace with your compiled proto definition)
const GreeterServiceDefinition: GreeterDefinition = {
  // @ts-ignore - In a real scenario, this would come from compiled protos
  name: 'Greeter',
  // @ts-ignore
  methods: {
    SayHello: {
      path: '/Greeter/SayHello',
      requestStream: false,
      responseStream: false,
      requestType: { type: 'HelloRequest' },
      responseType: { type: 'HelloResponse' },
    },
  },
};

async function main() {
  const channel = createChannel('localhost:50051');

  const clientFactory = createClientFactory()
    .use(createDeadlineClientMiddleware());

  const client: GreeterClient = clientFactory.create(GreeterServiceDefinition, channel);

  console.log('Client created with deadline middleware.');

  try {
    // Example 1: Call with a specific deadline (500 ms from now)
    const response1 = await client.sayHello({
      name: 'Alice',
    }, {
      deadline: Date.now() + 500, // Call will timeout if server doesn't respond in 500ms
    });
    console.log(`Response from SayHello (Alice): ${response1.message}`);
  } catch (error) {
    if (error instanceof ClientError && error.code === status.DEADLINE_EXCEEDED) {
      console.error('Call for Alice exceeded deadline!');
    } else {
      console.error('Error calling SayHello for Alice:', error);
    }
  }

  try {
    // Example 2: Call without an explicit deadline (will use any factory-wide default or gRPC's default)
    const response2 = await client.sayHello({
      name: 'Bob',
    });
    console.log(`Response from SayHello (Bob): ${response2.message}`);
  } catch (error) {
    console.error('Error calling SayHello for Bob:', error);
  }

  // To demonstrate a factory-wide default deadline:
  const clientFactoryWithDefaultDeadline = createClientFactory()
    .use(createDeadlineClientMiddleware())
    .use(async (call, options) => call.next(call, { ...options, deadline: Date.now() + 2000 })); // 2-second default

  const clientWithDefault: GreeterClient = clientFactoryWithDefaultDeadline.create(GreeterServiceDefinition, channel);

  try {
    console.log('\nAttempting call with 2-second default deadline...');
    const response3 = await clientWithDefault.sayHello({ name: 'Charlie' });
    console.log(`Response from SayHello (Charlie): ${response3.message}`);
  } catch (error) {
    if (error instanceof ClientError && error.code === status.DEADLINE_EXCEEDED) {
      console.error('Call for Charlie exceeded default deadline!');
    } else {
      console.error('Error calling SayHello for Charlie:', error);
    }
  }

  channel.close();
}

main().catch(console.error);

view raw JSON →