Skip to content

Commit 9a54f51

Browse files
authored
async-schema-fetching v2 (#72)
* async-schema-fetching v2 - moved kafka.send to happen after actual schema registration (in case registration fails and exception is thrown, it shouldn't reach kafka) - removed globalThis.kafkaProducer - removed kafka clientId & topic from config, because it should be compliant with consul API (only host, port & credentials, no other properties) - changed config.brokers to host & port, same thing with env vars - updated README * linter + updated README
1 parent 6e0a294 commit 9a54f51

17 files changed

+58
-53
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

88
## [Unreleased]
9+
10+
## [2.2.0] - 2021-11-23
11+
12+
### Added
13+
- New feature - asynchroneous notification of gateway via kafka to avoid polling & reduce schema inconsistency time. See [examples/gateway_service_kafka_notification] for gateway. Use env vars to configure schema-registry
14+
915
## [2.1.1] - 2021-11-08
1016

1117
### Updated

README.md

+6-4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Graphql schema storage as dockerized on-premise service for federated graphql ga
1717
- Provides UI for developers to see stored schema & its history diff
1818
- Stores & shows in UI persisted queries passed by the gateway for debugging
1919
- Stores service urls emulating managed federation: you no longer need to hardcode the services in your gateway's constructor, or rely on an additonal service (etcd, consul) for service discovery
20+
- Async schema registration of new schema with events to avoid polling (`schema-registry -> kafka -> gateway`)
2021

2122
<img width="1309" alt="Screenshot 2020-08-31 at 15 40 43" src="https://user-images.githubusercontent.com/445122/91720806-65985c00-eba0-11ea-8763-986b9f3f166b.png">
2223

@@ -27,7 +28,6 @@ Graphql schema storage as dockerized on-premise service for federated graphql ga
2728
- client tracking (for breaking changes)
2829
- schema usage tracking (for breaking changes)
2930
- separate ephemeral automatic PQs, registered by frontend (use cache only with TTL) from true PQs backend-registered persisted queries (use DB only)
30-
- async schema registration of new schema with events to avoid polling. `schema-registry -> kafka -> gateway`
3131
- integrate [inspector](https://graphql-inspector.com/docs/essentials/diff)
3232

3333
## Configuration
@@ -54,10 +54,13 @@ The following are the different environment variables that are looked up that al
5454
| REDIS_SECRET | Password used to connect to Redis | Empty |
5555
| ASSETS_URL | Controls the url that web assets are served from | localhost:6001 |
5656
| NODE_ENV | Specifies the environment. Use _production_ to load js/css from `dist/assets` | Empty |
57-
| ASYNC_SCHEMA_UPDATES | Specifies if experimental Async Schema Updates is Enabled | false |
57+
| ASYNC_SCHEMA_UPDATES | Specifies if async achema updates is enabled | false |
58+
| KAFKA_BROKER_HOST | Host name of the Kafka broker, used if ASYNC_SCHEMA_UPDATES = true | gql-schema-registry-kafka |
59+
| KAFKA_BROKER_PORT | Port used when connecting to Kafka, used if ASYNC_SCHEMA_UPDATES = true | 9092 |
5860

5961
For development we rely on docker network and use hostnames from `docker-compose.yml`.
60-
For dynamic service discovery, see `app/config.js`. Node service uses to connect to mysql & redis and change it if you install it with own setup. If you use dynamic service discovery (consul/etcd), edit `diplomat.js`
62+
Node service uses to connect to mysql & redis and change it if you install it with own setup.
63+
For dynamic service discovery (if you need multiple hosts for scaling), override `app/config.js` and `diplomat.js`
6164

6265
## Installation
6366

@@ -81,7 +84,6 @@ docker run -e DB_HOST=localhost -e DB_USERNAME=root pipedrive/graphql-schema-reg
8184

8285
### Docker-compose
8386

84-
8587
```
8688
git clone https://github.com/pipedrive/graphql-schema-registry.git && cd graphql-schema-registry
8789
docker-compose up

app/config.js

+2-6
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,8 @@ module.exports = {
2020
secret: process.env.REDIS_SECRET || '',
2121
},
2222
'gql-schema-registry-kafka': {
23-
clientId:
24-
process.env.KAFKA_CLIENT || 'graphql-schema-registry-server',
25-
brokers: process.env.KAFKA_BROKERS
26-
? process.env.KAFKA_BROKERS.split(',')
27-
: ['gql-schema-registry-kafka:9092'],
28-
topic: process.env.KAFKA_TOPIC || 'test-topic',
23+
host: process.env.KAFKA_BROKER_HOST || 'gql-schema-registry-kafka',
24+
port: process.env.KAFKA_BROKER_PORT || '9092',
2925
},
3026
},
3127
asyncSchemaUpdates: Boolean(process.env.ASYNC_SCHEMA_UPDATES || 'false'),

app/index.js

+3-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const express = require('express');
22
const logger = require('./logger');
33
const { get } = require('lodash');
44
const initGraphql = require('./graphql');
5-
const { producer } = require('./kafka/producer');
5+
const kafka = require('./kafka');
66
const config = require('./config');
77

88
const app = express();
@@ -105,12 +105,9 @@ exports.init = async () => {
105105
if (server) {
106106
return server;
107107
}
108+
108109
if (config.asyncSchemaUpdates) {
109-
producer()
110-
.then((p) => {
111-
globalThis.kafkaProducer = p;
112-
})
113-
.catch(console.error);
110+
kafka.init();
114111
}
115112

116113
server = app.listen(config.port, () => {

app/kafka/index.js

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
const { Kafka } = require('kafkajs');
2+
const diplomat = require('../diplomat');
3+
4+
const KAFKA_SCHEMA_REGISTRY =
5+
process.env.KAFKA_SCHEMA_REGISTRY || 'gql-schema-registry-kafka';
6+
7+
let producer = null;
8+
9+
exports.init = async () => {
10+
const { host, port } = diplomat.getServiceInstance(KAFKA_SCHEMA_REGISTRY);
11+
12+
const kafka = new Kafka({
13+
clientId: process.env.KAFKA_CLIENT || 'graphql-schema-registry-server',
14+
brokers: [`${host}:${port}`],
15+
});
16+
17+
producer = kafka.producer();
18+
await producer.connect();
19+
};
20+
21+
exports.send = (data) => {
22+
if (!producer) {
23+
throw new Error('Kafka producer not initialized');
24+
}
25+
26+
producer.send({
27+
topic: process.env.KAFKA_TOPIC || 'test-topic',
28+
messages: [{ value: JSON.stringify(data) }],
29+
});
30+
};
31+
32+
exports.KAFKA_SCHEMA_REGISTRY = KAFKA_SCHEMA_REGISTRY;

app/kafka/producer.js

-25
This file was deleted.

app/router/schema.js

+5-9
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@ const {
66
deactivateSchema,
77
diffSchemas,
88
} = require('../controller/schema');
9-
const diplomat = require('../diplomat');
109
const config = require('../config');
11-
const { KAFKA_SCHEMA_REGISTRY } = require('../kafka/producer');
12-
13-
const { topic } = diplomat.getServiceInstance(KAFKA_SCHEMA_REGISTRY);
10+
const kafka = require('../kafka');
1411

1512
exports.composeLatest = async (req, res) => {
1613
const schema = await getAndValidateSchema();
@@ -58,16 +55,15 @@ exports.push = async (req, res) => {
5855
})
5956
);
6057

58+
const data = await pushAndValidateSchema({ service });
59+
6160
if (config.asyncSchemaUpdates) {
62-
await globalThis.kafkaProducer.send({
63-
topic,
64-
messages: [{ value: 'Schema Updated!' }],
65-
});
61+
await kafka.send(data);
6662
}
6763

6864
return res.json({
6965
success: true,
70-
data: await pushAndValidateSchema({ service }),
66+
data,
7167
});
7268
};
7369

docker-compose.with-kafka-dev.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ services:
4040
- DB_SCHEMA_REGISTRY=gql-schema-registry-db
4141
- ASYNC_SCHEMA_UPDATES=true
4242
- KAFKA_CLIENT=graphql-schema-registry-server
43-
- KAFKA_BROKERS=gql-schema-registry-kafka:9092
43+
- KAFKA_BROKER_HOST=gql-schema-registry-kafka
44+
- KAFKA_BROKER_PORT=9092
4445
- KAFKA_TOPIC=test-topic
4546
volumes:
4647
- .:/app/

package-lock.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "graphql-schema-registry",
3-
"version": "2.1.1",
3+
"version": "2.2.0",
44
"description": "Graphql schema registry",
55
"main": "schema-registry.js",
66
"scripts": {

0 commit comments

Comments
 (0)