SapNwRfc icon indicating copy to clipboard operation
SapNwRfc copied to clipboard

Keep reference to generic server function delegates so they don't get GCed and crash the application

Open campersau opened this issue 1 year ago • 5 comments

Extracted the fix from https://github.com/huysentruitw/SapNwRfc/pull/53

Fixes https://github.com/huysentruitw/SapNwRfc/issues/56

campersau avatar Aug 23 '22 20:08 campersau

I'm looking forward to this making it into the library as I currently have it manually implemented in my code. I've run into one small thing while using it though and want to mention it. In my application, I need to be able to Stop/Start the RFC Server.

I can do a _server.Shutdown() and _server.Launch(), but if I fully dispose my ISapServer and re-create it, I run into the GC issue after launching my new instance. Generally, I think this is OK and works for my current purposes. However, it seems like the only way to really destroy the server and delegates is to fully recycle the application.

tom-j-irvine avatar Aug 24 '22 17:08 tom-j-irvine

@tom-j-irvine can you please show some code where you would run into the GC issue? Or are you referring to the implementation in #53 ?

campersau avatar Aug 24 '22 18:08 campersau

Here is what works:

private ISapServer _sapServer;

// ... lots of other code

private void StartRfcServer()
{
    // force shutdown if already running
    StopRfcServer(false);
    
    // start
    _logger.LogInformation("Starting RFC server");
    try
    {
        if (_sapServer == null) 
        {

            _sapServer = SapServer.Create(_config.GetRfcServerParameters());

            SapServer.InstallGenericServerFunctionHandler(
                _config.GetRfcDestinationParameters(),
                (connection, function) => HandleFunction(function)
                );
        }

        _sapServer.Launch();

        _logger.LogInformation("RFC server started");
    }
    catch (Exception ex)
    {
        _logger.LogError("Exception starting RFC server: {message}", ex.Message);
    }
    
}

private void StopRfcServer(bool logShutdown = true)
{
    if (_sapServer != null)
    {
        if (logShutdown) _logger.LogInformation("Stopping RFC server");
        try
        {
            _sapServer.Shutdown(2000);
            if (logShutdown) _logger.LogInformation("RFC server stopped");
        }
        catch (Exception ex)
        {
            _logger.LogWarning("Exception shutting down RFC server: {message}", ex.Message);
        }
    }
}

As I said, this works for my purposes. However, I had a version of the code where during shutdown, I would completely dispose the _sapServer and assign null back to it. Then, after starting it back up with Create and InstallGenericServerFunctionHandler, I would run into the GC issue.

I'm really not sure this matters, but there does seem to be something lingering if you create a server and try to destroy it. I imagine things could get funky if you tried to create multiple servers too, but hopefully no one would try to do that.

tom-j-irvine avatar Aug 24 '22 18:08 tom-j-irvine

Thanks! I will investigate it.

campersau avatar Aug 24 '22 18:08 campersau

It looks like that calling RfcInstallGenericServerFunction multiple times does not work. So I changed the code that calling SapServer.InstallGenericServerFunctionHandler multiple times will only set the user delegates and RfcInstallGenericServerFunction is just called the first time. Which avoids wrapping the users methods but introduces a few more static fields.

campersau avatar Aug 24 '22 20:08 campersau