Remoting спонсор перестает называться

У меня есть приложение, которое создает несколько доменов приложений в одном процессе и взаимодействует между ними посредством удаленного взаимодействия. Я создаю спонсоров для всех объектов, чтобы они не были GCed.

Но некоторые все равно оказались GCed. После некоторого расследования я определил, что в зависимости от InitialLeaseTime На моих удаленных объектах моих спонсоров либо никогда не вызывают, либо вызывают пару раз, а потом уже никогда.

Мой спонсор (я удалил некоторые проверки здравомыслия для краткости):

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;
        }
    }
}

Мой тестовый пример:

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;
    }
}

Если я оставлю InitialLeaseTime через 5 минут.NET по умолчанию мой спонсор никогда не будет вызван. Если я установлю его на 2 минуты, он будет вызываться дважды, а затем никогда. Если я установлю его на 1 минуту, он будет вызываться постоянно, и работать так, как я ожидал, будут работать значения по умолчанию.

Обновить

С тех пор я решил, что ILease Объекты самих моих спонсоров находятся в GCed. Они начинают со стандартного времени аренды 5 минут, которое объясняет, как часто звонят мои спонсоры. Когда я установил свой InitialLeaseTime до 1 минуты ILease объекты постоянно обновляются из-за их RenewOnCallTime по умолчанию 2 минуты.

Что я делаю неправильно? Я не вижу способа создать спонсоров для объектов аренды моих спонсоров.

2 ответа

Прошло много времени с тех пор, как был задан этот вопрос, но я столкнулся с этим сегодня, и через пару часов я понял это. 5-минутная проблема связана с тем, что у вашего Спонсора, который должен наследовать от MarshalByRefObject, также есть связанная аренда. Он создан в вашем клиентском домене, а ваш хост-домен имеет прокси для ссылки в вашем клиентском домене. Срок действия истекает через 5 минут по умолчанию, если вы не переопределите метод InitializeLifetimeService() в своем классе Спонсора, или у этого спонсора есть собственный спонсор, не позволяющий ему истечь.

Как ни странно, я преодолел это, вернув Null в переопределении спонсора InitializeLifetimeService(), чтобы предоставить ему неограниченную временную аренду, и я создал свою реализацию ISponsor, чтобы удалить ее в MBRO для хоста.

Я опубликовал очень похожую проблему и ответил: "Функция обновления спонсора перестает вызываться". Это может быть даже та же проблема.

Я решил эту проблему, разместив спонсора на сервере, а не на клиенте. Спонсор серверной стороны, кажется, достаточно надежно вызван, чтобы поддерживать удаленный объект в живых. Я знаю, что это не будет очень безопасным решением во многих случаях, потому что клиент должен активно отключить спонсора, а не просто позволить истечению срока аренды.

Другие вопросы по тегам