2

I've got an app which creates several AppDomains in a single process and communicates between them via remoting. I create sponsors for all objects to prevent them from being GCed.

But, some ended up being GCed anyway. After some investigation I've determined that depending on the InitialLeaseTime set on my remote objects, my sponsors are either never called or get called a couple times and then never again.

My sponsor (I've removed some sanity checking for brevity):

class Sponsor : MarshalByRefObject, ISponsor, IDisposable
{
    ILease lease;

    public Sponsor(MarshalByRefObject mbro)
    {
        lease = (ILease)RemotingServices.GetLifetimeService(mbro);
        lease.Register(this);
    }

    public TimeSpan Renewal(ILease lease)
    {
        return this.lease != null ? lease.InitialLeaseTime : TimeSpan.Zero;
    }

    public void Dispose()
    {
        if(lease != null)
        {
            lease.Unregister(this);
            lease = null;
        }
    }
}

My test case:

class Program : MarshalByRefObject
{
    static void Main(string[] args)
    {
        AppDomain ad = AppDomain.CreateDomain("Remote");

        Program obj = (Program)ad.CreateInstanceAndUnwrap(
            typeof(Program).Assembly.FullName,
            typeof(Program).FullName);

        using (new Sponsor(obj))
        {
            // sleep for 6 minutes.
            // 5 seems to be the point where it gets GCed.
            Thread.Sleep(6 * 60 * 1000); 

            // throws a RemotingException
            obj.Ping();
        }
    }

    void Ping()
    {
    }

    public override object InitializeLifetimeService()
    {
        ILease lease = (ILease)base.InitializeLifetimeService();

        if (lease.CurrentState == LeaseState.Initial)
        {
            // this is the .NET default. if used, the lease is never renewed.
            //lease.InitialLeaseTime = TimeSpan.FromMinutes(5);

            // if uncommented, lease is renewed twice and never again.
            //lease.InitialLeaseTime = TimeSpan.FromMinutes(2);

            // if uncommented, lease is renewed continually.
            //lease.InitialLeaseTime = TimeSpan.FromMinutes(1);
        }

        return lease;
    }
}

If I leave the InitialLeaseTime at 5 minutes, the .NET default, my sponsor will never be called. If I set it to 2 minutes, it will be called twice and then never again. If I set it to 1 minute, it will be called continually and work how I expected the default values to work.

Update

I've since determined that the ILease objects of my sponsors themselves are being GCed. They start out with the default 5min lease time, which explains how often my sponsors are being called. When I set my InitialLeaseTime to 1min, the ILease objects are continually renewed due to their RenewOnCallTime being the default of 2min.

What am I doing wrong? I don't see a way to create sponsors for the lease objects of my sponsors.

Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
  • your test values suggests that the sponsor used was a client object and also expired(by default values) then was removed from sponsors list and not renewed the lease – Davi Fiamenghi Feb 03 '14 at 02:04
  • 1
    I think thats why `System.Runtime.Remoting.Lifetime.ClientSponsor.InitializeLifetimeService` returns null – Davi Fiamenghi Feb 03 '14 at 17:53
  • don't you also have to disconnect the sponsor itself afterwards?? Otherwise it will live forever. I see that you are disconnecting the lease, but you don't disconnect the sponsor in your dispose method.. I tried the disconnect on a sponsor and it returns the True value, so it must be a thing. i.e. avoid using Using. – Alex Jul 18 '20 at 16:24

2 Answers2

4

It's been a long time since this question was asked, but I ran into this today and after a couple hours, I figured it out. The 5 minutes issue is because your Sponsor which has to inherit from MarshalByRefObject also has an associated lease. It's created in your Client domain and your Host domain has a proxy to the reference in your Client domain. This expires after the default 5 minutes unless you override the InitializeLifetimeService() method in your Sponsor class or this sponsor has its own sponsor keeping it from expiring.

Funnily enough, I overcame this by returning Null in the sponsor's InitializeLifetimeService() override to give it an infinite timespan lease, and I created my ISponsor implementation to remove that in a Host MBRO.

1

I posted a very similar problem and answer "Sponsor's Renewal function stops being called". It might even be the same problem.

I've worked around it by putting the sponsor on the server instead of the client. The server side sponsor seems to be reliably called enough to keep the remote object alive. I know this won't be a very safe solution in many cases because the client must actively disconnect the sponsor instead of just letting the lease expire.

Community
  • 1
  • 1
user1318499
  • 1,327
  • 11
  • 33
  • My current workaround is to manage my own leases. Sadly there does not seem to be any guidance from Microsoft on how to use it properly. – Cory Nelson Feb 03 '14 at 02:29