Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

leaking eventcore driver because there are still active handles #2245

Open
mengu opened this issue Dec 26, 2018 · 46 comments
Open

leaking eventcore driver because there are still active handles #2245

mengu opened this issue Dec 26, 2018 · 46 comments

Comments

@mengu
Copy link

mengu commented Dec 26, 2018

hello everyone

i need to build a websocket server that needs to talk to cups. i've got that part sorted out. i've tried to give the websocket example a try.

vibe.d version 0.8.4: compiles well however when i quit the server, i got this message: leaking eventcore driver because there are still active handles
vibe.d version 0.8.5.beta: does not even run, it exits with the same error.

os: macOS high sierra (10.13.6)
kernel: Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64
dmd: DMD64 D Compiler v2.083.1
ldc: LDC - the LLVM D compiler (1.7.0):

here's the sample code:

import std.stdio;
import std.string;
import std.conv;
import core.time;

import vibe.core.core : sleep;
import vibe.core.log;
import vibe.http.router : URLRouter;
import vibe.http.server;
import vibe.http.websockets : WebSocket, handleWebSockets;

void handleWebSocketConnection(scope WebSocket socket) {
  int counter = 0;
  logInfo("Got new web socket connection.");
  while (true) {
    sleep(1.seconds);
    if (!socket.connected) break;
    counter++;
    logInfo("Sending '%s'.", counter);
    socket.send(counter.to!string);
  }
  logInfo("Client disconnected.");
}

shared static this() {
  auto router = new URLRouter;
  router.get("/ws", handleWebSockets(&handleWebSocketConnection));

  auto settings = new HTTPServerSettings;
  settings.port = 8080;
  settings.bindAddresses = ["::1", "127.0.0.1"];
  listenHTTP(settings, router);
}

@thaven
Copy link
Contributor

thaven commented Dec 27, 2018

Looks like you just forgot about explicitly closing any open websockets when the server process is being terminated, hence 'there are still active handles'. For a simple test like this, that may probably be ignored.

@mengu
Copy link
Author

mengu commented Dec 27, 2018

this actually happens even without any connections @thaven. also, with 0.8.5 beta the app does not even start.

@CosmicToast
Copy link

CosmicToast commented Feb 27, 2019

This is reproducible on my system (and in my project).
Further, it is reproducible with the app_skeleton example (even terminating almost immediately after launch) (I haven't tried any other ones, but I would suspect that applies there as well).
In app_skeleton, I'm seeing the message twice, verbatim:

Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 6 (streamListen)
Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 6 (streamListen)

I see this behavior in the following environments:
a)
os: Arch Linux amd64
kernel: Linux LapToast 4.20.12-arch1-1-ARCH #1 SMP PREEMPT Sat Feb 23 15:11:34 UTC 2019 x86_64 GNU/Linux
dmd: DMD64 D Compiler v2.084.1
LDC - the LLVM D compiler (1.14.0):

b)
os: Ubuntu Cosmic (as LXD guest under Alpine Edge)
kernel: Linux william 4.19.25-0-vanilla #1-Alpine SMP Mon Feb 25 08:42:23 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
dmd: DMD64 D Compiler v2.084.1
ldc: LDC - the LLVM D compiler (1.11.0):

EDIT: This is particularly annoying because the trailing sockets (which apparently do exist) prevent whatever application is/was running from restarting (it fails to bind).
fuser -k is no help, and one seemingly needs to wait for the connection to drop.
Perhaps closing the eventloop should forcefully terminate any current connections?

@Geod24
Copy link
Contributor

Geod24 commented Mar 11, 2019

Yep, seeing it with:

module app;

import vibe.http.router;
import vibe.web.rest;

shared static this ()
{
    auto router = new URLRouter();
    auto settings = new HTTPServerSettings("0.0.0.0");
    settings.port = 4245;
    router.registerRestInterface(new Server1());
    listenHTTP(settings, router);
}

@safe:
interface API1 { string getGreeting(); }
class Server1 : API1 { string getGreeting() { return "API1";  } }

As well...

@dedupely
Copy link

I'm getting that error message with Redis as well on vibe 0.8.4

@judepereira
Copy link

Okay, so this is because runApplication(); is missing. A call to runApplication(); is required immediately after listenHTTP. I can reproduce this behaviour without runApplication():

import vibe.d;

class CheckTODO {
    @path("/health")
    void health(HTTPServerRequest req, HTTPServerResponse res) {
        res.writeBody("ok");
    }
}

void main() {
    auto router = new URLRouter;
    router.registerWebInterface(new CheckTODO);

    auto settings = new HTTPServerSettings;
    settings.port = 8080;
    listenHTTP(settings, router);
    // runApplication();
}
Failed to listen on 0.0.0.0:8080
Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 9 (streamListen)
Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 9 (streamListen)

However, if I uncomment runApplication, it works just fine.

@CosmicToast
Copy link

I'm experiencing this with vibe-d's provided entrypoint, which should just run runApplication (https://github.com/vibe-d/vibe.d/blob/master/core/vibe/appmain.d), so there may be more to it than that.

@judepereira
Copy link

Ah, I missed that, sorry.

@dedupely
Copy link

dedupely commented Jun 26, 2019 via email

@CosmicToast
Copy link

CosmicToast commented Jun 26, 2019

Exit code is still 0 in my experience.
However, it results in the port not being bindable for a short period of time afterwards, which is very annoying for server restarts and/or development.

@dedupely
Copy link

dedupely commented Jun 26, 2019 via email

@dedupely
Copy link

dedupely commented Jul 8, 2019

I'm still having issues with this and strangely it appears that the port is not being let go of (not sure if this makes sense). Because on restart it crashes to due to the port being in use. Maybe 'leaking eventcore' has something to do with the http listener not closing?

@s-ludwig
Copy link
Member

s-ludwig commented Jul 9, 2019

The port reuse issue will be fixed with vibe-core 1.7.0 (already available in the latest beta), the default for SO_REUSEADDR accidentally changed to 0 in a previous release.

A generic, built-in way to wait for all incoming HTTP requests to complete is still missing, but listenHTTP returns a HTTPListener that has a stopListening method to close the listening socket.

@dedupely
Copy link

dedupely commented Jul 9, 2019

The port reuse issue will be fixed with vibe-core 1.7.0 (already available in the latest beta), the default for SO_REUSEADDR accidentally changed to 0 in a previous release.

A generic, built-in way to wait for all incoming HTTP requests to complete is still missing, but listenHTTP returns a HTTPListener that has a stopListening method to close the listening socket.

Thanks this is what I needed to hear. It will be an easy fix once we have 1.7.0 in production. Can I use HTTPServerOption.reusePort in the meantime? You mentioned the default but is this configurable?

@dedupely
Copy link

dedupely commented Aug 1, 2019

Hmm, this actually appears to have fixed the issue:

I updated to 1.7.0 beta2 (probably does not change much in this leaking case).

Because my app uses it's own main and I call runEventLoop(); to start the even loop, it appeared something else was not being cleaned up.

As per @s-ludwig 's instruction, I did this:

  auto l = listenHTTP(settings, router);

  runEventLoop();

  l.stopListening;

This was what I got before:

main thread exit
Event loop exit reason (exit flag=false): exited
Event loop done (scheduled tasks=0, waiters=1, thread exit=false).
Thread exit main (index 0) (main=true)
Main thread exiting
Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 9 (streamListen)
Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 9 (streamListen)

This is what I get now:

main thread exit
Event loop exit reason (exit flag=false): exited
Event loop done (scheduled tasks=0, waiters=1, thread exit=false).
[main(----) INF] Stopped to listen for HTTP requests on :::8089
Thread exit main (index 0) (main=true)
Main thread exiting

So it looks like that was the problem. Event loop exit doesn't seem to close the listening socket created in listenHTTP.

@schveiguy
Copy link
Contributor

I'm having a similar issue. I've just now tried to make sure all sockets are closed so I don't get this error message. I believe I'm handling all the database connections, and I'm on 1.7.0 of vibe-core. When I look at the trace output, the sockets that are left are the streamSockets used by the web server to handle incoming requests. Looking at the code, it appears they should be closed, but there's no trace to say a socket is closed.

@schveiguy
Copy link
Contributor

Just to clarify, my messages say streamSocket, NOT streamListen, and I added the stopListening call, it doesn't fix it.

@dedupely
Copy link

I still get this as well, but I'm using a number of different services like phobos tcp sockets, postgres and beanstalkd. Any one of these could be contributing. However, I've noticed I get it less running the stopListening at the end. Honestly I don't know enough about Vibe.d under the hood to really make educated guesses on this.

@schveiguy
Copy link
Contributor

The underlying issue of WHY this happens is that the event driver is cleaning up synchronously, but items that will be cleaned up by the GC are still holding resources. Since the GC is the last thing that cleans up, the event driver has to leak its resources to avoid segfaults. Before these messages you'd get a segfault every close. But I would expect the core vibe-d fibers to properly release sockets when they are done.

@schveiguy
Copy link
Contributor

More info: it's the redis session store that is not closing. I'm "cheating" by using tupleof so I can close the driver sockets, but they still leak (I'm using instrumented code that prints out when sockets are closed). Will continue to investigate, I'm hoping if I fix this problem, the messages go away. Note that if I close the app while there are still keepalive sockets open, those will leak. I'd like to see those go away too at shutdown, or at least have a way to wait for them to close. But if you do wait for the timeout, they don't leak.

@schveiguy
Copy link
Contributor

OK, FINALLY! I figured out why this is happening.

The redis session store doesn't provide a way to release unused connections, so as I said, I was cheating and using tupleof to get the ConnectionPool out of the RedisClient.

Then I was calling removeUnused to clear out all the connections still open. Each RedisConnection is a class, so there is no problem reference-wise there BUT, it only provides property access to the TCPConnection via conn(). I was calling close on that, thinking it would release the resource, but there was still a reference to the socket inside the class itself! THAT wasn't being cleaned up until the GC ran, which is why the driver was leaking.

The solution here is to expose the removeUnused functionality so the session store can be properly cleaned up before shutdown.

@Geod24
Copy link
Contributor

Geod24 commented Sep 26, 2019

This is redis-specific though. So the simple programs shown above exhibit a different issue ?

@schveiguy
Copy link
Contributor

schveiguy commented Sep 26, 2019

So the examples above seem to come from not closing down the listening socket (which it seems like folks have already fixed). But in general, ANY class-based thing that holds onto a descriptor may leak the driver. The only way to fix is to provide cleanup mechanisms that can be called on program termination, and to have them called. Aside from the redis issue, I need to also update mysql-native so it has a way to do this. Because it seems most of these wrappers hide a private ConnectionPool, it makes things difficult to call the cleanup function directly, and honestly, I'd rather have it implemented correctly in one place.

What WOULD be nice is if the call leaking the driver would identify the way that descriptor was used. For example, if it's a file, say "last used to open /x/y/z" or if it's a socket, "last used as a TCP connection to X.X.X.X:Y", to help narrow down where it's leaking from. As with most leaks, it's easy to tell something has leaked, but really difficult to tell where it leaked from. Having those clues can save hours of work (as it did take me hours to instrument everything to find the right place it was opened). Maybe an eventcore option to store the appropriate data for describing the source of the leak.

I also just realized, the messages are all being printed twice. Not sure why that is.

@schveiguy
Copy link
Contributor

Added a PR for fixing the redis issue.

@chadjoan
Copy link

chadjoan commented Jun 6, 2020

I just experienced this with the "Hello World!" example. This time I'm playing with Vibe.d on FreeBSD (12.1). I'm pretty sure I ran into it many months ago as well, that time when playing with Vibe.d on Gentoo Linux. That was likely also in the "Hello World!" example.

To reproduce the problem, in brief:

  • Make a new project using dub init <project-name> -t vibe.d as described at the top of the documentation page.
  • cd path/to/project
  • Optionally, add "versions": [ "VibeHighEventPriority" ] to dub.json, or versions "VibeHighEventPriority" to dub.sdl, as described in vibe-d/vibe-core issue #205.
    • The bug described here still happens without doing this, but it'll save you a few minutes of futile hammering-of-the-ctrl-c before pulling out a bigger hammer and running kill -9 $vibe_testing_pid, and thus you'll get cleaner output that stands a better chance of matching what I quote below.
  • Build the thing: dub build -b debug
  • Run it, then hit Ctrl-C:
$ ./vibe-testing 
[main(----) INF] Listening for requests on http://[::1]:8080/
[main(----) INF] Listening for requests on http://127.0.0.1:8080/
[main(----) INF] Please open http://127.0.0.1:8080/ in your browser.
^C[main(----) INF] Received signal 2. Shutting down.
Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 8 (streamListen)
   FD 9 (streamListen)
Warning (thread: main): leaking eventcore driver because there are still active handles
   FD 8 (streamListen)
   FD 9 (streamListen)

Thankfully, on this system and with this config (FreeBSD 12.1; w/ VibeHighEventPriority if it matters) the bug/warning doesn't prevent subsequent runs of the test executable. I can ctrl-C and rerun immediately over and over again to my heart's content. It can even restart effectively instantly after I visit the "Hello World!" webpage. In my case, It just looks disturbing, because of the warning message.

The source/app.d contents I had at the start, with bug present as described above, looked like this:

import vibe.vibe;

void main()
{
        auto settings = new HTTPServerSettings;
        settings.port = 8080;
        settings.bindAddresses = ["::1", "127.0.0.1"];
        listenHTTP(settings, &hello);

        logInfo("Please open http://127.0.0.1:8080/ in your browser.");
        runApplication();
}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
        res.writeBody("Hello, World!");
}

I made it go away by modifying it according to @s-ludwig 's suggestion and @dedupely 's example earlier in this thread:

import vibe.vibe;

void main()
{
        auto settings = new HTTPServerSettings;
        settings.port = 8080;
        settings.bindAddresses = ["::1", "127.0.0.1"];
        auto listener = listenHTTP(settings, &hello);
        scope(exit)
                listener.stopListening();

        logInfo("Please open http://127.0.0.1:8080/ in your browser.");
        runApplication();
}

void hello(HTTPServerRequest req, HTTPServerResponse res)
{
        res.writeBody("Hello, World!");
}

Note the auto listener = listenHTTP(settings, &hello); and scope(exit) listener.stopListening();.

With that, the output becomes:

$ ./vibe-testing 
[main(----) INF] Listening for requests on http://[::1]:8080/
[main(----) INF] Listening for requests on http://127.0.0.1:8080/
[main(----) INF] Please open http://127.0.0.1:8080/ in your browser.
^C[main(----) INF] Received signal 2. Shutting down.
[main(----) INF] Stopped to listen for HTTP requests on ::1:8080
[main(----) INF] Stopped to listen for HTTP requests on 127.0.0.1:8080

Yay! No more leaking eventcore drivers.

I suspect that this particular manifestation can be fixed with documentation and example changes. The idiomatic code I see in the example above and on the documentation webpage seems to follow the same pattern (omitting the listener assignment statement and later .stopListening() call), and this pattern is requisite for this problem to happen. I suggest using something like the modified example above as the default example. Then it will not only copy, paste, and run without warning messages (and possible blocked sockets), but it shows learners that the object returned from listenHTTP holds network resources (it's all in the "stopListening" name) as well as how to release those resources.

I'd try to provide a PR, but I already looked for the source of that app.d "Hello World!" example and couldn't find it quickly. I hope it at least helps to know that this can happen in basic examples.

Thank you all.

@schveiguy
Copy link
Contributor

The underlying issue here is that one does not get detailed information about what handles are leaking, and when they were opened. It would be huge to be able to identify what the handles were doing. FD 8 and FD 9 is useless information. streamListen is useful, but not entirely descriptive. I'd like to see at a minimum all the information that vibe-core knows about it (i.e. if it's a socket, what type (TCP/UDP), IP address/port it's connected to, if possible when it was opened).

It would be even better to get a stack trace from the place the last time the socket was used (enabled only with a certain flag of course). I think this should be doable.

The root cause of all these is -- you didn't release a resource. But finding out which resource and why it was opened is very difficult from the messages given.

I also agree the default vibe-d server should clean up itself properly.

@chadjoan
Copy link

chadjoan commented Jun 6, 2020

I... totally agree and also really like good error messages.

I hope I didn't distract from that. I just wanted to provide an easy (I hope) solution for an adoption pitfall that arises as one consequence of the resource management and error reporting issues.

By that logic, it seems that this could probably spawn a few separate issues, in addition to the redis one that you handled: fix idioms in documentation, more specific+useful error messages, error messages are printed twice, less error-prone resource management (scope or ref-count non-memory resources by default?), and maybe more. I worry that I would do a poor job of writing those because I lack specifics and am not very familiar with vibe.d (yet).

@jblachly
Copy link
Contributor

In my testing, scope(exit)... sometimes, but not always, fixes the problem. In some cases, after ctl-c the other thread cleans itself up and closes. In other cases, it does not.

@kinexis-uk
Copy link

Hi all. thanks for the helpful suggestions.

Full disclosure, I'm not that good at coding. intermediate at best.

What i did notice on my setup though (Catalina, fresh D install, new vibe-d template project) is that NO MATTER WHAT I DO - scope(exit) or otherwise - i can only rerun the vibe-d application after refreshing my web browser one time.

Steps to reproduce:

  1. Launch vibe-d app
  2. Ctrl-C
  3. Attempt to rerun multiple times - unsuccessfully.
  4. Switch to - or open new - web browser.
  5. Navigate to or refresh localhost:8080 - App appears JUST ONCE in browser even AFTER Ctrl-C (you read correctly)
  6. After the app appears that ONE TIME in the browser, vibe-d app successfully restarts

With scope(exit) listener.stopListening() I get the "Stopped listening" log ONLY after ONE browser refresh following Ctrl-C.

Without scope(exit) i do not receive that log message at all.

I don't know much about whats going on architecturally but it seems that a remnant of the app is sitting somewhere after Ctrl-C is pressed and remains until at least one request is made for/of that remnant.

I'm not sure if any of this is helpful as I currently only speak noob, but it reproduces every time...

@SelimOzel
Copy link

I also came across this problem and wrote about it on DLang forums [1]. This is the toy example [2] I've been working on to test.

[1] https://forum.dlang.org/post/finhhdbacjeybbjohgxv@forum.dlang.org
[2] https://github.com/SelimOzel/vibe_noLeaks

@Geod24
Copy link
Contributor

Geod24 commented Jun 23, 2021

Still happening, although now vibe-core is a bit more verbose:

[main(----) INF] Listening for requests on http://0.0.0.0:4245/
^C[main(----) INF] Received signal 2. Shutting down.
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 6 (streamListen)
Use '-debug=EventCoreLeakTrace' to show where the instantiation happened
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 6 (streamListen)
Use '-debug=EventCoreLeakTrace' to show where the instantiation happened

@schveiguy
Copy link
Contributor

Whoa, are those messages accurate? Like with a switch I can see a stack trace of where a leaked handle was allocated? That's exactly what needs to happen to find these issues!

@SelimOzel
Copy link

Hey Steve. I have had similar errors before. Any tools you suggest to get the stack trace? Happy to give it a try.

@schveiguy
Copy link
Contributor

Just look at the message above. it says what to do to get a trace (define debug=EventCoreLeakTrace). I'm just curious how it works.

@JackStouffer
Copy link

JackStouffer commented Aug 25, 2021

@schveiguy @s-ludwig This is still an issue. I was able to get a stack trace using the debug flag.

Platform:

macOS 11.4 Big Sur
DMD 2.097.2
dub 1.26.1
vibe-d 0.9.3

Steps to reproduce:

  • Create a dub project with the code from the "Simple app.d file with minimal routing" example from https://vibed.org/docs
  • run dub with the EventCoreLeakTrace debug flag
  • Open the page in the browser
  • Ctrl-C in the terminal
  • Using Activity Monitor, you can see the process is still running
  • Reload the page in the browser
  • The stack trace is printed and the process exits

Output

$ dub

...

Running ecommerce
[main(----) INF] Listening for requests on http://[::]:8080/
Failed to listen on 0.0.0.0:8080
^C[main(----) INF] Received signal 2. Shutting down.

Then reload the page in the browser and this is printed to the console.

Warning (thread: main): leaking eventcore driver because there are still active handles                                                                                         [0:02:09]
  FD 10 (streamListen)
    Created by;
      ??:? core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x10cc053e8]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x10cc05390]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:413 nothrow @nogc @safe eventcore.driver.StreamListenSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamListenSocketFD, eventcore.drivers.posix.sockets.StreamListenSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamListenSocketSlot) [0x10cbb4d2e]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/sockets.d:262 nothrow @safe eventcore.driver.StreamListenSocketFD eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets.listenStream(scope std.socket.Address, eventcore.driver.StreamListenOptions, void delegate(eventcore.driver.StreamListenSocketFD, eventcore.driver.StreamSocketFD, eventcore.driver.RefAddress) nothrow @safe) [0x10cbbd2d6]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/net.d:118 @safe vibe.core.net.TCPListener vibe.core.net.listenTCP(ushort, void delegate(vibe.core.net.TCPConnection) nothrow @safe, immutable(char)[], vibe.core.net.TCPListenOptions) [0x10cb3f4a3]
      /Users/Jack/.dub/packages/vibe-d-0.9.3/vibe-d/http/vibe/http/server.d:2047 nothrow @safe vibe.core.net.TCPListener vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe).doListen(vibe.http.server.HTTPServerContext, bool, bool, bool, bool) [0x10c9c8fc0]
      /Users/Jack/.dub/packages/vibe-d-0.9.3/vibe-d/http/vibe/http/server.d:2083 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe) [0x10c9c8d77]
      source/app.d:6 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTP!(vibe.http.server.HTTPServerSettings).listenHTTP(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe) [0x10c8a8761]
      source/app.d:6 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTP!(vibe.http.server.HTTPServerSettings).listenHTTP(vibe.http.server.HTTPServerSettings, vibe.http.server.HTTPServerRequestHandler) [0x10c8a86a6]
      source/app.d:10 _Dmain [0x10c880e77]
  FD 13 (streamSocket)
    Created by;
      ??:? core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x10cc053e8]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x10cc05390]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:413 nothrow @nogc @safe eventcore.driver.StreamSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamSocketFD, eventcore.drivers.posix.sockets.StreamSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamSocketSlot) [0x10cbb4996]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/sockets.d:292 nothrow @safe void eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets.onAccept(eventcore.driver.FD) [0x10cbbd5e0]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:370 nothrow @safe void eventcore.drivers.posix.driver.PosixEventLoop.notify!(0).notify(ulong) [0x10cbb3de6]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/kqueue.d:82 nothrow @trusted bool eventcore.drivers.posix.kqueue.KqueueEventLoopBase.doProcessEventsBase(core.time.Duration) [0x10cbb61d5]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/cfrunloop.d:88 extern (C) nothrow @safe void eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop.processKqueue(eventcore.internal.corefoundation.__CFFileDescriptor*, eventcore.internal.corefoundation.CFOptionFlags, void*) [0x10cbb100c]
      ??:? __CFFileDescriptorPerform [0x7fff20629c17]
      ??:? __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ [0x7fff205c197b]
      ??:? __CFRunLoopDoSource0 [0x7fff205c18e3]
      ??:? __CFRunLoopDoSources0 [0x7fff205c1663]
      ??:? __CFRunLoopRun [0x7fff205c008b]
      ??:? CFRunLoopRunSpecific [0x7fff205bf64b]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/cfrunloop.d:62 nothrow @trusted bool eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop.doProcessEvents(core.time.Duration) [0x10cbb0f09]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:246 nothrow @safe eventcore.driver.ExitReason eventcore.drivers.posix.driver.PosixEventDriverCore!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop, eventcore.drivers.timer.LoopTimeoutTimerDriver, eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets).PosixEventDriverEvents, eventcore.drivers.posix.processes.PosixEventDriverProcesses!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverProcesses).PosixEventDriverCore.processEvents(core.time.Duration) [0x10cbb31ec]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/task.d:889 nothrow @safe eventcore.driver.ExitReason vibe.core.task.TaskScheduler.waitAndProcess() [0x10cb61442]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/core.d:219 nothrow @safe int vibe.core.core.runEventLoop() [0x10cb33439]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/core.d:110 @safe int vibe.core.core.runApplication(immutable(char)[][]*) [0x10cb33261]
      source/app.d:18 _Dmain [0x10c880e7e]
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 10 (streamListen)
    Created by;
      ??:? core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x10cc053e8]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x10cc05390]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:413 nothrow @nogc @safe eventcore.driver.StreamListenSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamListenSocketFD, eventcore.drivers.posix.sockets.StreamListenSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamListenSocketSlot) [0x10cbb4d2e]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/sockets.d:262 nothrow @safe eventcore.driver.StreamListenSocketFD eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets.listenStream(scope std.socket.Address, eventcore.driver.StreamListenOptions, void delegate(eventcore.driver.StreamListenSocketFD, eventcore.driver.StreamSocketFD, eventcore.driver.RefAddress) nothrow @safe) [0x10cbbd2d6]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/net.d:118 @safe vibe.core.net.TCPListener vibe.core.net.listenTCP(ushort, void delegate(vibe.core.net.TCPConnection) nothrow @safe, immutable(char)[], vibe.core.net.TCPListenOptions) [0x10cb3f4a3]
      /Users/Jack/.dub/packages/vibe-d-0.9.3/vibe-d/http/vibe/http/server.d:2047 nothrow @safe vibe.core.net.TCPListener vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe).doListen(vibe.http.server.HTTPServerContext, bool, bool, bool, bool) [0x10c9c8fc0]
      /Users/Jack/.dub/packages/vibe-d-0.9.3/vibe-d/http/vibe/http/server.d:2083 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe) [0x10c9c8d77]
      source/app.d:6 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTP!(vibe.http.server.HTTPServerSettings).listenHTTP(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe) [0x10c8a8761]
      source/app.d:6 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTP!(vibe.http.server.HTTPServerSettings).listenHTTP(vibe.http.server.HTTPServerSettings, vibe.http.server.HTTPServerRequestHandler) [0x10c8a86a6]
      source/app.d:10 _Dmain [0x10c880e77]
  FD 13 (streamSocket)
    Created by;
      ??:? core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x10cc053e8]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x10cc05390]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:413 nothrow @nogc @safe eventcore.driver.StreamSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamSocketFD, eventcore.drivers.posix.sockets.StreamSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamSocketSlot) [0x10cbb4996]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/sockets.d:292 nothrow @safe void eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets.onAccept(eventcore.driver.FD) [0x10cbbd5e0]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:370 nothrow @safe void eventcore.drivers.posix.driver.PosixEventLoop.notify!(0).notify(ulong) [0x10cbb3de6]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/kqueue.d:82 nothrow @trusted bool eventcore.drivers.posix.kqueue.KqueueEventLoopBase.doProcessEventsBase(core.time.Duration) [0x10cbb61d5]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/cfrunloop.d:88 extern (C) nothrow @safe void eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop.processKqueue(eventcore.internal.corefoundation.__CFFileDescriptor*, eventcore.internal.corefoundation.CFOptionFlags, void*) [0x10cbb100c]
      ??:? __CFFileDescriptorPerform [0x7fff20629c17]
      ??:? __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ [0x7fff205c197b]
      ??:? __CFRunLoopDoSource0 [0x7fff205c18e3]
      ??:? __CFRunLoopDoSources0 [0x7fff205c1663]
      ??:? __CFRunLoopRun [0x7fff205c008b]
      ??:? CFRunLoopRunSpecific [0x7fff205bf64b]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/cfrunloop.d:62 nothrow @trusted bool eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop.doProcessEvents(core.time.Duration) [0x10cbb0f09]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:246 nothrow @safe eventcore.driver.ExitReason eventcore.drivers.posix.driver.PosixEventDriverCore!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop, eventcore.drivers.timer.LoopTimeoutTimerDriver, eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets).PosixEventDriverEvents, eventcore.drivers.posix.processes.PosixEventDriverProcesses!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverProcesses).PosixEventDriverCore.processEvents(core.time.Duration) [0x10cbb31ec]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/task.d:889 nothrow @safe eventcore.driver.ExitReason vibe.core.task.TaskScheduler.waitAndProcess() [0x10cb61442]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/core.d:219 nothrow @safe int vibe.core.core.runEventLoop() [0x10cb33439]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/core.d:110 @safe int vibe.core.core.runApplication(immutable(char)[][]*) [0x10cb33261]
      source/app.d:18 _Dmain [0x10c880e7e]

@Geod24
Copy link
Contributor

Geod24 commented Aug 25, 2021

The zombie issue has been fixed yesterday: #2596
Will release a new vibe-core so you can use it.

@Geod24
Copy link
Contributor

Geod24 commented Aug 25, 2021

@JackStouffer : We were also discussing this in here.
Those docs definitely need an update.

@schveiguy
Copy link
Contributor

Hm... that's not my experience though. When I kill the app, it shuts down, it doesn't still handle any requests. There was a bug a while ago that had this happening on Linux, see vibe-d/vibe-core#205.

The leaking of resources I don't think is anything that vibe or vibe-core can deal with, because it's the application that isn't properly cleaning itself up. But what is important is the stack trace showing where the leaked handle was allocated. Thanks for the printout, @JackStouffer, It looks a little rough, but seems to get the job done (kinda funny seeing the DefaultTraceInfo ctor always at the top).

@JackStouffer
Copy link

@schveiguy Well if there's anything I can add to my code as a work around to clean up the server from a Ctrl-C, please let me know.

@Geod24 I've updated to the latest version of vibe-core and I'm still getting the same issue. Used the same testing steps as before.

dub.json:

{
	"authors": [
		"Jack Stouffer"
	],
	"copyright": "Copyright © 2021, Jack Stouffer",
	"debugVersions": [
		"EventCoreLeakTrace"
	],
	"dependencies": {
		"vibe-core": "~>1.19.0",
		"vibe-d-postgresql": "~>3.0.1",
		"vibe-d:crypto": "~>0.9.3",
		"vibe-d:data": "~>0.9.3",
		"vibe-d:inet": "~>0.9.3",
		"vibe-d:stream": "~>0.9.3",
		"vibe-d:tls": "~>0.9.3",
		"vibe-d:web": "~>0.9.3"
	},
	"description": "ecommerce",
	"license": "proprietary",
	"name": "ecommerce"
}

app.d

import vibe.core.core;
import vibe.http.router;
import vibe.http.server;

void index(HTTPServerRequest req, HTTPServerResponse res)
{
	res.render!("index.dt", req);
}

void main()
{
	auto router = new URLRouter;
	router.get("/", &index);
	
	auto settings = new HTTPServerSettings;
	settings.port = 8080;
	
	listenHTTP(settings, router);
	
	runApplication();
}

Stack trace

Warning (thread: main): leaking eventcore driver because there are still active handles                                                                                        [11:17:15]
  FD 10 (streamListen)
    Created by;
      ??:? core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x1047a79b8]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x1047a7960]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:413 nothrow @nogc @safe eventcore.driver.StreamListenSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamListenSocketFD, eventcore.drivers.posix.sockets.StreamListenSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamListenSocketSlot) [0x104719fb2]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/sockets.d:262 nothrow @safe eventcore.driver.StreamListenSocketFD eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets.listenStream(scope std.socket.Address, eventcore.driver.StreamListenOptions, void delegate(eventcore.driver.StreamListenSocketFD, eventcore.driver.StreamSocketFD, eventcore.driver.RefAddress) nothrow @safe) [0x10472255a]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/net.d:118 @safe vibe.core.net.TCPListener vibe.core.net.listenTCP(ushort, void delegate(vibe.core.net.TCPConnection) nothrow @safe, immutable(char)[], vibe.core.net.TCPListenOptions) [0x1046df28b]
      /Users/Jack/.dub/packages/vibe-d-0.9.3/vibe-d/http/vibe/http/server.d:2047 nothrow @safe vibe.core.net.TCPListener vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe).doListen(vibe.http.server.HTTPServerContext, bool, bool, bool, bool) [0x1045499e0]
      /Users/Jack/.dub/packages/vibe-d-0.9.3/vibe-d/http/vibe/http/server.d:2083 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe) [0x104549797]
      source/app.d:8 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTP!(vibe.http.server.HTTPServerSettings).listenHTTP(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe) [0x1044afb85]
      source/app.d:8 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTP!(vibe.http.server.HTTPServerSettings).listenHTTP(vibe.http.server.HTTPServerSettings, vibe.http.server.HTTPServerRequestHandler) [0x1044afaca]
      source/app.d:12 _Dmain [0x10448efdb]
  FD 13 (streamSocket)
    Created by;
      ??:? core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x1047a79b8]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x1047a7960]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:413 nothrow @nogc @safe eventcore.driver.StreamSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamSocketFD, eventcore.drivers.posix.sockets.StreamSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamSocketSlot) [0x104719c1a]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/sockets.d:292 nothrow @safe void eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets.onAccept(eventcore.driver.FD) [0x104722864]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:370 nothrow @safe void eventcore.drivers.posix.driver.PosixEventLoop.notify!(0).notify(ulong) [0x10471906a]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/kqueue.d:82 nothrow @trusted bool eventcore.drivers.posix.kqueue.KqueueEventLoopBase.doProcessEventsBase(core.time.Duration) [0x10471b459]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/cfrunloop.d:88 extern (C) nothrow @safe void eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop.processKqueue(eventcore.internal.corefoundation.__CFFileDescriptor*, eventcore.internal.corefoundation.CFOptionFlags, void*) [0x104716290]
      ??:? __CFFileDescriptorPerform [0x7fff20629c17]
      ??:? __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ [0x7fff205c197b]
      ??:? __CFRunLoopDoSource0 [0x7fff205c18e3]
      ??:? __CFRunLoopDoSources0 [0x7fff205c1663]
      ??:? __CFRunLoopRun [0x7fff205c008b]
      ??:? CFRunLoopRunSpecific [0x7fff205bf64b]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/cfrunloop.d:62 nothrow @trusted bool eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop.doProcessEvents(core.time.Duration) [0x10471618d]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:246 nothrow @safe eventcore.driver.ExitReason eventcore.drivers.posix.driver.PosixEventDriverCore!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop, eventcore.drivers.timer.LoopTimeoutTimerDriver, eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets).PosixEventDriverEvents, eventcore.drivers.posix.processes.PosixEventDriverProcesses!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverProcesses).PosixEventDriverCore.processEvents(core.time.Duration) [0x104718470]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/task.d:889 nothrow @safe eventcore.driver.ExitReason vibe.core.task.TaskScheduler.waitAndProcess() [0x1047013fa]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/core.d:219 nothrow @safe int vibe.core.core.runEventLoop() [0x1046d3e01]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/core.d:110 @safe int vibe.core.core.runApplication(immutable(char)[][]*) [0x1046d3c29]
      source/app.d:20 _Dmain [0x10448efe2]
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 10 (streamListen)
    Created by;
      ??:? core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x1047a79b8]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x1047a7960]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:413 nothrow @nogc @safe eventcore.driver.StreamListenSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamListenSocketFD, eventcore.drivers.posix.sockets.StreamListenSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamListenSocketSlot) [0x104719fb2]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/sockets.d:262 nothrow @safe eventcore.driver.StreamListenSocketFD eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets.listenStream(scope std.socket.Address, eventcore.driver.StreamListenOptions, void delegate(eventcore.driver.StreamListenSocketFD, eventcore.driver.StreamSocketFD, eventcore.driver.RefAddress) nothrow @safe) [0x10472255a]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/net.d:118 @safe vibe.core.net.TCPListener vibe.core.net.listenTCP(ushort, void delegate(vibe.core.net.TCPConnection) nothrow @safe, immutable(char)[], vibe.core.net.TCPListenOptions) [0x1046df28b]
      /Users/Jack/.dub/packages/vibe-d-0.9.3/vibe-d/http/vibe/http/server.d:2047 nothrow @safe vibe.core.net.TCPListener vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe).doListen(vibe.http.server.HTTPServerContext, bool, bool, bool, bool) [0x1045499e0]
      /Users/Jack/.dub/packages/vibe-d-0.9.3/vibe-d/http/vibe/http/server.d:2083 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTPPlain(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe) [0x104549797]
      source/app.d:8 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTP!(vibe.http.server.HTTPServerSettings).listenHTTP(vibe.http.server.HTTPServerSettings, void delegate(vibe.http.server.HTTPServerRequest, vibe.http.server.HTTPServerResponse) @safe) [0x1044afb85]
      source/app.d:8 @safe vibe.http.server.HTTPListener vibe.http.server.listenHTTP!(vibe.http.server.HTTPServerSettings).listenHTTP(vibe.http.server.HTTPServerSettings, vibe.http.server.HTTPServerRequestHandler) [0x1044afaca]
      source/app.d:12 _Dmain [0x10448efdb]
  FD 13 (streamSocket)
    Created by;
      ??:? core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x1047a79b8]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x1047a7960]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:413 nothrow @nogc @safe eventcore.driver.StreamSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamSocketFD, eventcore.drivers.posix.sockets.StreamSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamSocketSlot) [0x104719c1a]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/sockets.d:292 nothrow @safe void eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets.onAccept(eventcore.driver.FD) [0x104722864]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:370 nothrow @safe void eventcore.drivers.posix.driver.PosixEventLoop.notify!(0).notify(ulong) [0x10471906a]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/kqueue.d:82 nothrow @trusted bool eventcore.drivers.posix.kqueue.KqueueEventLoopBase.doProcessEventsBase(core.time.Duration) [0x10471b459]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/cfrunloop.d:88 extern (C) nothrow @safe void eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop.processKqueue(eventcore.internal.corefoundation.__CFFileDescriptor*, eventcore.internal.corefoundation.CFOptionFlags, void*) [0x104716290]
      ??:? __CFFileDescriptorPerform [0x7fff20629c17]
      ??:? __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ [0x7fff205c197b]
      ??:? __CFRunLoopDoSource0 [0x7fff205c18e3]
      ??:? __CFRunLoopDoSources0 [0x7fff205c1663]
      ??:? __CFRunLoopRun [0x7fff205c008b]
      ??:? CFRunLoopRunSpecific [0x7fff205bf64b]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/cfrunloop.d:62 nothrow @trusted bool eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop.doProcessEvents(core.time.Duration) [0x10471618d]
      /Users/Jack/.dub/packages/eventcore-0.9.17/eventcore/source/eventcore/drivers/posix/driver.d:246 nothrow @safe eventcore.driver.ExitReason eventcore.drivers.posix.driver.PosixEventDriverCore!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop, eventcore.drivers.timer.LoopTimeoutTimerDriver, eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverSockets).PosixEventDriverEvents, eventcore.drivers.posix.processes.PosixEventDriverProcesses!(eventcore.drivers.posix.cfrunloop.CFRunLoopEventLoop).PosixEventDriverProcesses).PosixEventDriverCore.processEvents(core.time.Duration) [0x104718470]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/task.d:889 nothrow @safe eventcore.driver.ExitReason vibe.core.task.TaskScheduler.waitAndProcess() [0x1047013fa]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/core.d:219 nothrow @safe int vibe.core.core.runEventLoop() [0x1046d3e01]
      /Users/Jack/.dub/packages/vibe-core-1.19.0/vibe-core/source/vibe/core/core.d:110 @safe int vibe.core.core.runApplication(immutable(char)[][]*) [0x1046d3c29]
      source/app.d:20 _Dmain [0x10448efe2]

@schveiguy
Copy link
Contributor

@JackStouffer As noted near the top of this thread, you need to clean up the listener: #2245 (comment)

However, I don't think it should still keep the process running if you didn't do this. I am not experiencing that, but I'm also cleaning up my listener, so not sure.

@JackStouffer
Copy link

Still getting the same issue.

Here's my updated app.d

import vibe.core.core;
import vibe.http.router;
import vibe.http.server;

void index(HTTPServerRequest req, HTTPServerResponse res)
{
	res.render!("index.dt", req);
}

void main()
{
	auto router = new URLRouter;
	router.get("/", &index);
	
	auto settings = new HTTPServerSettings;
	settings.bindAddresses = ["127.0.0.1"];
	settings.port = 8080;

	auto listener = listenHTTP(settings, router);
	
	runApplication();

	// cleans up event loop
	listener.stopListening();
}

@AlexanderZhirov
Copy link

AlexanderZhirov commented Feb 15, 2024

I'm also getting problems with descriptors.

System:
  Host: solus Kernel: 6.6.16-273.current arch: x86_64 bits: 64 Desktop: Budgie
    v: 10.9.1 Distro: Solus 4.5 resilience
Machine:
  Type: Desktop System: Gigabyte product: N/A v: N/A
    serial: <superuser required>
  Mobo: Gigabyte model: Z77-DS3H v: x.x serial: <superuser required>
    UEFI: American Megatrends v: F9 date: 09/19/2012
CPU:
  Info: quad core Intel Core i7-3770 [MT MCP] speed (MHz): avg: 1775
    min/max: 1600/3900
 void startServer(int port, string[] addresses, string data) {
    auto router = setupRouters(data);

    auto memorySessionStore = new MemorySessionStore;
    auto settingsHTTP = new HTTPServerSettings;

    settingsHTTP.errorPageHandler = toDelegate(&page404);
    settingsHTTP.sessionStore = memorySessionStore;
    settingsHTTP.port = port.to!ushort;
    settingsHTTP.bindAddresses = ["::1"] ~ addresses;

    auto listenerHTTP = listenHTTP(settingsHTTP, router);
    scope (exit) { listenerHTTP.stopListening(); }
    runApplication();
}
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 11 (streamSocket)
    Created by;
      ??:? @nogc core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x55e66d3ef0b0]
      ??:? @nogc core.runtime.DefaultTraceInfo core.lifetime.emplace!(core.runtime.DefaultTraceInfo).emplace(core.runtime.DefaultTraceInfo) [0x55e66d44d613]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x55e66d3ef009]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/driver.d:425 nothrow @nogc @safe eventcore.driver.StreamSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamSocketFD, eventcore.drivers.posix.sockets.StreamSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamSocketSlot) [0x55e66d3ced3a]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/sockets.d:303 nothrow @safe void eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverSockets.onAccept(eventcore.driver.FD) [0x55e66d3a7bbf]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/driver.d:372 nothrow @safe void eventcore.drivers.posix.driver.PosixEventLoop.notify!(0).notify(ulong) [0x55e66d3ce5c6]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/epoll.d:56 nothrow @trusted bool eventcore.drivers.posix.epoll.EpollEventLoop.doProcessEvents(core.time.Duration) [0x55e66d3a3212]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/driver.d:248 nothrow @safe eventcore.driver.ExitReason eventcore.drivers.posix.driver.PosixEventDriverCore!(eventcore.drivers.posix.epoll.EpollEventLoop, eventcore.drivers.timer.LoopTimeoutTimerDriver, eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.epoll.EpollEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverSockets).PosixEventDriverEvents, eventcore.drivers.posix.processes.PosixEventDriverProcesses!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverProcesses).PosixEventDriverCore.processEvents(core.time.Duration) [0x55e66d3a2b10]
      ../../../../../.dub/packages/vibe-core-2.8.1/vibe-core/source/vibe/core/task.d:954 nothrow @safe eventcore.driver.ExitReason vibe.core.task.TaskScheduler.waitAndProcess(core.time.Duration) [0x55e66d372ce9]
      ../../../../../.dub/packages/vibe-core-2.8.1/vibe-core/source/vibe/core/core.d:219 nothrow @safe int vibe.core.core.runEventLoop() [0x55e66d346441]
      ../../../../../.dub/packages/vibe-core-2.8.1/vibe-core/source/vibe/core/core.d:110 @safe int vibe.core.core.runApplication(immutable(char)[][]*) [0x55e66d346261]
      source/server.d:41 void source.server.startServer(int, immutable(char)[][], immutable(char)[]) [0x55e66d13f02f]
      source/shkolaspo.d:38 _Dmain [0x55e66d13f320]
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 11 (streamSocket)
    Created by;
      ??:? @nogc core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x55e66d3ef0b0]
      ??:? @nogc core.runtime.DefaultTraceInfo core.lifetime.emplace!(core.runtime.DefaultTraceInfo).emplace(core.runtime.DefaultTraceInfo) [0x55e66d44d613]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x55e66d3ef009]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/driver.d:425 nothrow @nogc @safe eventcore.driver.StreamSocketFD eventcore.drivers.posix.driver.PosixEventLoop.initFD!(eventcore.driver.StreamSocketFD, eventcore.drivers.posix.sockets.StreamSocketSlot).initFD(ulong, eventcore.drivers.posix.driver.FDFlags, eventcore.drivers.posix.sockets.StreamSocketSlot) [0x55e66d3ced3a]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/sockets.d:303 nothrow @safe void eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverSockets.onAccept(eventcore.driver.FD) [0x55e66d3a7bbf]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/driver.d:372 nothrow @safe void eventcore.drivers.posix.driver.PosixEventLoop.notify!(0).notify(ulong) [0x55e66d3ce5c6]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/epoll.d:56 nothrow @trusted bool eventcore.drivers.posix.epoll.EpollEventLoop.doProcessEvents(core.time.Duration) [0x55e66d3a3212]
      ../../../../../.dub/packages/eventcore-0.9.28/eventcore/source/eventcore/drivers/posix/driver.d:248 nothrow @safe eventcore.driver.ExitReason eventcore.drivers.posix.driver.PosixEventDriverCore!(eventcore.drivers.posix.epoll.EpollEventLoop, eventcore.drivers.timer.LoopTimeoutTimerDriver, eventcore.drivers.posix.events.PosixEventDriverEvents!(eventcore.drivers.posix.epoll.EpollEventLoop, eventcore.drivers.posix.sockets.PosixEventDriverSockets!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverSockets).PosixEventDriverEvents, eventcore.drivers.posix.processes.PosixEventDriverProcesses!(eventcore.drivers.posix.epoll.EpollEventLoop).PosixEventDriverProcesses).PosixEventDriverCore.processEvents(core.time.Duration) [0x55e66d3a2b10]
      ../../../../../.dub/packages/vibe-core-2.8.1/vibe-core/source/vibe/core/task.d:954 nothrow @safe eventcore.driver.ExitReason vibe.core.task.TaskScheduler.waitAndProcess(core.time.Duration) [0x55e66d372ce9]
      ../../../../../.dub/packages/vibe-core-2.8.1/vibe-core/source/vibe/core/core.d:219 nothrow @safe int vibe.core.core.runEventLoop() [0x55e66d346441]
      ../../../../../.dub/packages/vibe-core-2.8.1/vibe-core/source/vibe/core/core.d:110 @safe int vibe.core.core.runApplication(immutable(char)[][]*) [0x55e66d346261]
      source/server.d:41 void source.server.startServer(int, immutable(char)[][], immutable(char)[]) [0x55e66d13f02f]
      source/shkolaspo.d:38 _Dmain [0x55e66d13f320]

@foresto
Copy link

foresto commented Feb 25, 2024

This problem shows up any time I store a UDPConnection in a class instance, even if it's short-lived, never used, and close() is called before exit.

Reproducer:

import vibe.core.core;
import vibe.core.net;

class Leaky
    {
    UDPConnection conn;
    this(UDPConnection conn) { this.conn = conn; }
    }

void main()
    {
    auto conn = listenUDP(1234); // -debug=EventCoreLeakTrace flags this line
    scope(exit) conn.close();
    auto leaky = new Leaky(conn);
    runTask({ exitEventLoop(); });
    runEventLoop();
    }
Warnings at exit (normal build)
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 6 (datagramSocket)
Use '-debug=EventCoreLeakTrace' to show where the instantiation happened
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 6 (datagramSocket)
Use '-debug=EventCoreLeakTrace' to show where the instantiation happened
Warnings at exit (EventCoreLeakTrace build)
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 6 (datagramSocket)
    Created by;
      ??:? @nogc core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x7f246bb8f316]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x7f246bb8ef12]
      ../../.dub/packages/eventcore/0.9.28/eventcore/source/eventcore/drivers/posix/driver.d:425 [0x556dbadad906]
      ../../.dub/packages/eventcore/0.9.28/eventcore/source/eventcore/drivers/posix/sockets.d:781 [0x556dbadb7e43]
      ../../.dub/packages/eventcore/0.9.28/eventcore/source/eventcore/drivers/posix/sockets.d:720 [0x556dbadb7a2d]
      ../../../../.dub/packages/vibe-core/2.8.2/vibe-core/source/vibe/core/net.d:1002 [0x556dbad9117c]
      ../../../../.dub/packages/vibe-core/2.8.2/vibe-core/source/vibe/core/net.d:286 [0x556dbad91337]
      vibe_eventcore_leak.d:12 [0x556dbad1f3a7]
      ??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])*).runAll() [0x7f246bba2aeb]
      ??:? _d_run_main2 [0x7f246bba2901]
      ??:? _d_run_main [0x7f246bba274d]
      /usr/lib/ldc/x86_64-linux-gnu/include/d/core/internal/entrypoint.d:42 [0x556dbad1f631]
      ??:? [0x7f246b81f249]
      ??:? __libc_start_main [0x7f246b81f304]
      ??:? [0x556dbad1f220]
Warning (thread: main): leaking eventcore driver because there are still active handles
  FD 6 (datagramSocket)
    Created by;
      ??:? @nogc core.runtime.DefaultTraceInfo core.runtime.DefaultTraceInfo.__ctor() [0x7f246bb8f316]
      ??:? object.Throwable.TraceInfo core.runtime.defaultTraceHandler(void*) [0x7f246bb8ef12]
      ../../.dub/packages/eventcore/0.9.28/eventcore/source/eventcore/drivers/posix/driver.d:425 [0x556dbadad906]
      ../../.dub/packages/eventcore/0.9.28/eventcore/source/eventcore/drivers/posix/sockets.d:781 [0x556dbadb7e43]
      ../../.dub/packages/eventcore/0.9.28/eventcore/source/eventcore/drivers/posix/sockets.d:720 [0x556dbadb7a2d]
      ../../../../.dub/packages/vibe-core/2.8.2/vibe-core/source/vibe/core/net.d:1002 [0x556dbad9117c]
      ../../../../.dub/packages/vibe-core/2.8.2/vibe-core/source/vibe/core/net.d:286 [0x556dbad91337]
      vibe_eventcore_leak.d:12 [0x556dbad1f3a7]
      ??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])*).runAll() [0x7f246bba2aeb]
      ??:? _d_run_main2 [0x7f246bba2901]
      ??:? _d_run_main [0x7f246bba274d]
      /usr/lib/ldc/x86_64-linux-gnu/include/d/core/internal/entrypoint.d:42 [0x556dbad1f631]
      ??:? [0x7f246b81f249]
      ??:? __libc_start_main [0x7f246b81f304]
      ??:? [0x556dbad1f220]

Workarounds I've found so far:

  • Instead of storing a UDPConnection in class instances, pass it as an argument to every method that needs it.
  • Store UDPConnection in structs instead of classes.
  • Store UDPConnection in a scope class instance. (This is incompatible with @safe.)
  • Allocate a UDPConnection with new, copy the listenUDP() result to it, store a pointer to it in class instances, and use a scope guard to explicitly close() the connection before program exit.

However, having to clutter function signatures with repetitive arguments, give up classes, forbid @safe, or impose instantiation restrictions and other hoops on calling code, just to avoid a load of alarming output at exit, makes Vibe unappealing.

The fact that UDPConnection is a struct makes this behavior especially surprising, since most structs can be contained, copied, put on the GC heap, etc. without consequences.

Surely there must be a way for a Vibe socket handle to live in class without restrictions or complaints, just as a file descriptor can. Maybe UDPConnection.close() or the destructor need some work?

Tested with vibe-core 2.8.2 on linux.

@dedupely
Copy link

dedupely commented Mar 7, 2024

I'm still getting this issue. Right now it's mostly because of redis. I went back to vibe.d redis again. Once again the problem perisists. For me the stack trace points to RedisReply and then finally the Streaming library in vibe.d.

I'm don't know the inner workings of how this happens, but if we can catch and count these FDs, why can't they be cleaned up on shutdown? Is there some type of place of return where they're no longer touchable? This seems to happen a lot in runTask but it also happens in the mean thread (if I get it correctly).

I've tried all of the above and nothing seems to work. The reason I think this is an issue long term is that I'm not sure if it's indefinitely binding FDs and eating them up one at the time in the environment. Like can we eventually run out of descriptors at some point?

Anyways, aside from that which may actually be a problem, my error logs in k8s are really cluttered because I can't turn this message off either unless I completely disable warnings which is not good for reporting.

@schveiguy
Copy link
Contributor

@dedupely
Copy link

dedupely commented Mar 8, 2024

@schveiguy Found it! I was calling that function above and then later the redis.quit(); function which was actually opening a new connection and then causing the leak. I used only releaseUnusedConnections and that works perfectly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests