web-dev-qa-db-ja.com

graphql-Java-SpringBootでサブスクリプションを使用する方法は?

プロジェクトでは、graphql-Javaおよびを使用しますpostgreSQLデータベースを使用したSpringBoot。ここで、バージョン3.0.0で公開されているサブスクリプション機能を使用したいと思います。残念ながら、サブスクリプション機能の適用に関する情報はあまり成熟していません。

サブスクリプションでgraphql-Javaを使用してリアルタイム機能を実現するためのアプローチはどのようになっていますか?

8
muetzerich

最近のgraphql-Javaバージョンでは、サブスクリプションが完全にサポートされています。サブスクリプションのDataFetcherは_org.reactivestreams.Publisher_を返す必要があり、graphql-Javaが結果に対するクエリ関数のマッピングを処理します。

この機能はうまく機能しています 文書化されています そして 完全な例 公式リポジトリで利用可能なWebソケットを使用しています。

Spring固有の実装に関しては、Publisher

サブスクリプションが着信するたびに、新しいリスナーを作成して、アプリケーションコンテキストcontext.addApplicationListener(listener)に登録します。これは正しいPublisherに公開されます。例えば。 DataFetcher内:

_// Somehow create a publisher, probably using Spring's Reactor project. Or RxJava.
Publisher<ResultObject> publisher = ...; 
//The listener reacts on application events and pushes new values through the publisher
ApplicationListener listener = createListener(publisher);
context.addApplicationListener(listener);
return publisher;
_

Webソケットが切断された場合、またはイベントストリームが終了したことが何らかの理由でわかった場合は、必ずリスナーを削除する必要があります。

私は実際にこれを試したことがありません、気をつけてください、私はただ声を出して考えています。

もう1つのオプションは、Reactorを直接使用することです(Spring WebFluxの有無にかかわらず)。 ReactorとWebSocketを使用したサンプルがあります( GraphQL SPQR Spring Boot Starter を介して) ここ

次のようにPublisherを作成します。

_//This is really just a thread-safe wrapper around Map<String, Set<FluxSink<Task>>>
private final ConcurrentMultiRegistry<String, FluxSink<Task>> subscribers = new ConcurrentMultiRegistry<>();

@GraphQLSubscription
public Publisher<Task> taskStatusChanged(String taskId) {
    return Flux.create(subscriber -> subscribers.add(taskId, subscriber.onDispose(() -> subscribers.remove(taskId, subscriber))), FluxSink.OverflowStrategy.LATEST);
}
_

そして、次のように他の場所(おそらく関連するミューテーションまたはリアクティブストレージ)から新しい値をプッシュします。

_subscribers.get(taskId).forEach(subscriber -> subscriber.next(task));
_

例えば。

_@GraphQLMutation
public Task updateTask(@GraphQLNonNull String taskId, @GraphQLNonNull Status status) {
    Task task = repo.byId(taskId); //find the task
    task.setStatus(status); //update the task
    repo.save(task); //persist the task
    //Notify all the subscribers following this task
    subscribers.get(taskId).forEach(subscriber -> subscriber.next(task));
    return task;
}
_

SPQR Spring Starterを使用すると、Apollo互換のサブスクリプション実装を取得するために必要なのはこれだけです。

2
kaqqao

SpringBootと統合するためにlibをスパイクしていたのと同じ問題が発生しました。 graphql-Javaを見つけましたが、スキーマレベルで「サブスクリプション」のみをサポートしているようで、この機能の国境を越えたサポートは実行していません。つまり、自分で実装する必要があるかもしれません。

https://github.com/graphql-Java/graphql-Java/blob/master/docs/schema.rst#subscription-support を参照してください。

0
Yang