How to close EventSource connection on Firebase server using .NET HttpClient with Firebase REST Streaming API

779 views Asked by At

I am using the .NET HttpClient to implement the Firebase Streaming Rest API, which itself is supporting the EventSource/Server-Sent Events protocol.

Documentation for this API is here: https://www.firebase.com/docs/rest/api/#section-streaming

My implementation shown below works properly to connect to Firebase and get my data, running inside a Windows Service which self-updates its business logic and then calls GetAndProcessFirebaseHttpResponse as a new Task every 10 minutes.

The problem is that, when I look in my Firebase Dashboard, the number of concurrent connections increases by 1 every time the Task runs, and I cannot seem to tell Firebase that the connection should be closed on the Firebase side and no further data sent.

Here is a simplified example of my code that I put into a sample app. Every time I call GetAndProcessFirebaseHttpResponse, another concurrent connection increments on my Firebase dashboard, and that connection persists even after I cancel the task (via CancellationSourceToken.Token.ThrowIfCancellationRequested()):

    public void GetAndProcessFirebaseHttpResponse(CancellationTokenSource cancellationTokenSource)
    {
        HttpResponseMessage httpResponse = ListenAsync().Result;

        using (httpResponse)
        {
            using (Stream contentStream = httpResponse.Content.ReadAsStreamAsync().Result)
            {
                using (StreamReader contentStreamReader = new StreamReader(contentStream))
                {
                    while (true)
                    {
                        if (cancellationTokenSource.IsCancellationRequested)
                        {
                            httpResponse.RequestMessage.Dispose();
                        }

                        cancellationTokenSource.Token.ThrowIfCancellationRequested();

                        string read = contentStreamReader.ReadLineAsync().Result;

                        // Process the data here
                    }
                }
            }
        }
    }

    private async Task<HttpResponseMessage> ListenAsync()
    {
        // Create HTTP Client which will allow auto redirect as required by Firebase
        HttpClientHandler httpClientHandler = new HttpClientHandler();
        httpClientHandler.AllowAutoRedirect = true;

        HttpClient httpClient = new HttpClient(httpClientHandler, true);
        httpClient.BaseAddress = new Uri(_firebasePath);
        httpClient.Timeout = TimeSpan.FromSeconds(60);

        string requestUrl = _firebasePath + ".json?auth=" + _authSecret;
        Uri requestUri = new Uri(requestUrl);

        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri);
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("text/event-stream"));

        HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
        response.EnsureSuccessStatusCode();

        return response;
    }

The HttpResponseMessage, Stream, StreamReader, HttpRequestMessage are all disposed. HttpClient is not, because it is recommended that it does not need to be (see, Do HttpClient and HttpClientHandler have to be disposed?). These disposals naturally release resources on the client, however I would guess that they communicate nothing to the Firebase server about the need to close the connection on the Firebase end.

My question is: using the .NET HttpClient with the Firebase REST Streaming API, how can I communicate to the Firebase REST endpoint that I am done with the connection and that it should be closed on the Firebase side?

0

There are 0 answers