0

I think I'm facing a possible memory leak with the GCP PubSub PublisherClient implementation in .NET Core. I wrote "I think" because to be fair I'm not even sure I'm using it properly (and this is why I'm posting this question here).

The app is a .NET Core Web API. Here's an extract of the implementation I have:

public class GoogleTopicPublisher : IAsyncDisposable
    {
        private readonly TopicName _topic;
        private readonly string _apiToken;
        private readonly ILogger<GoogleTopicPublisher> _logger;
        private readonly Lazy<Task<PublisherClient>> _lazyPublisher;

        public GoogleTopicPublisher(string projectId, string topicId, string apiToken,
            ILogger<GoogleTopicPublisher> logger)
        {
            _apiToken = apiToken;
            _topic = new TopicName(projectId, topicId);
            _logger = logger;

            _lazyPublisher = new Lazy<Task<PublisherClient>>(() => PublisherClient.CreateAsync(_topic));
        }

        public async Task PublishAsync(PubSubEnvelope envelope)
        { 
            var messageData = Newtonsoft.Json.JsonConvert.SerializeObject(envelope);

            var message = new PubsubMessage()
            {
                Data = ByteString.CopyFromUtf8(messageData),
                Attributes =
                    {
                        {"token", _apiToken }
                    }
            };

            var publisher = await _lazyPublisher.Value;
            await publisher.PublishAsync(message);

            GC.Collect();
            GC.WaitForPendingFinalizers();
        }

        public async ValueTask DisposeAsync()
        {
            if (!_lazyPublisher.IsValueCreated)
                return;

            var publisher = _lazyPublisher.Value.Result;
            await publisher.ShutdownAsync(TimeSpan.FromSeconds(15));
        }
    }

The whole GoogleTopicPublisher class is registered as Singleton. As you can see, I'm instantiating the Publisher using an async Lazy to avoid creating a new instance every time I have to publish a message.

The pain point is the calls to the GC: without them, I can see the memory usage growing and growing, till the whole application runs out of memory and gets restarted.

Now my questions:

  • is it a good practice to instantiate the PublisherClient this way? If not, is there a better way?
  • can I avoid in any way the calls to the GC?

thanks!

David Guida
  • 950
  • 9
  • 19
  • From [this question](https://stackoverflow.com/questions/12265598/is-correct-to-use-gc-collect-gc-waitforpendingfinalizers) it looks like the call of the GC can be causing a deadllock – Louis C Jun 17 '20 at 23:47
  • Do you take in consideration how .net core GC strategy works? Do you find the solution? – hsd Jan 19 '21 at 20:20
  • unfortunately no, I did not find a solution to this :( – David Guida Jan 20 '21 at 02:44

0 Answers0