在具有多个WFE的服务器场环境中部署计时器作业的最佳实践

ash*_*rya 7 sharepoint sharepoint-2007 timer-jobs sharepoint-2010

我有一个计时器工作,我想每天只运行一次,为整个农场.我如何能

  1. 在多个WFE环境中部署它?我是否在每个WFE中运行stsadm -o deploysolution命令,或者只运行我要运行它的那个?
  2. 我应该在哪里激活该功能?它应该仅从特定的WFE激活吗?
  3. 什么应该是SPJobLockType的值.

Tim*_*res 7

看起来您需要一个服务器场范围的功能,它安装运行此作业的服务.我是这样做的(使用同事写的代码,说实话,但他不是这样).

使用功能事件接收器创建feature.xml文件.

<Feature
  Id="..."
  Title="..."
  Description="..."
  Scope="Farm"
  Version="1.0.0.0"
  Hidden="FALSE"
  ReceiverAssembly="XXX.FarmService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxx"
  ReceiverClass="XXX.FarmService.XXXFarmFeatureEventReceiver"
  xmlns="http://schemas.microsoft.com/sharepoint/">
</Feature>
Run Code Online (Sandbox Code Playgroud)

在事件接收器内:

public override void OnFeatureActivated(SPFeatureReceiverProperties properties)
    {
        try
        {
            SPFarm farm = SPFarm.Local;

            // Get Service, if it already exists
            JobService myService = null; // JobService is a subclass of SPService
            foreach (SPService service in farm.Services)
            {
                if (String.Compare(service.Name, JobService.XXXServiceName, true) == 0)
                {
                    myService = (service as JobService);
                    break;
                    }
                }

                if (cegService == null)
                {
                    // Create service
                    myService = new JobService(farm);
                    myService.Update();

                    // Create service instances
                    JobServiceInstance myServiceInstance; // JobServiceInstance is a subclas of SPServiceInstance
                    foreach (SPServer server in farm.Servers)
                    {
                        myServiceInstance = new JobServiceInstance(server, myService);
                        myServiceInstance.Update();
                    }
                }

                // Dayly schedule 
                SPDailySchedule schedule = new SPDailySchedule();
                schedule.BeginHour = 1;
                schedule.EndHour = 1;
                schedule.BeginMinute = 0;
                schedule.EndMinute = 59;

                // Our own job; JobCheckDocDates is a subclass of SPJobDefinition
                JobCheckDocDates newJob = new JobCheckDocDates(cegService, null, SPJobLockType.Job);
                newJob.Schedule = schedule;
                newJob.Update();
                myService.JobDefinitions.Add(newJob);
                myService.Update();
            }
            catch (Exception e)
            {
                Logger.Error("[" + properties.Feature.Definition.DisplayName + "] Error during feature activation", e);
            }
        }        
Run Code Online (Sandbox Code Playgroud)

这将在服务器场中的每个服务器上创建一个服务.

关于子类的更多细节:

public class JobCheckDocDates: Common.BaseJob
{
    /// <summary>
    /// The job name
    /// </summary>
    public static string JobName = "XXX job";

    /// <summary>
    /// Constructor
    /// </summary>
    public JobCheckDocDates() : base() { }

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="service"></param>
    /// <param name="server"></param>
    /// <param name="lockType"></param>
    public JobCheckDocDates(SPService service, SPServer server, SPJobLockType lockType)
            : base(JobName, service, server, lockType) { }
Run Code Online (Sandbox Code Playgroud)

...

当然还有Execute方法.

public class JobService : SPService 
{
    public static string XXXServiceName = "XXX Service";

    public override string DisplayName
    {
        get
        {
            return XXXServiceName;
        }
    }

    public override string TypeName
    {
        get
        {
            return "XXX Service Type";
        }
    }

    /* An empty public constructor required for serialization. */
    public JobService() { }

    public JobService(SPFarm farm)
          : base(XXXServiceName, farm)
    {         
    }
}


    public class JobServiceInstance : SPServiceInstance
    {
        /// <summary>
        /// Eos Service Instance Name
        /// </summary>
        public static string XXXServiceInstanceName = "XXXServiceInstance";

        /// <summary>
        /// Manage Link
        /// </summary>
        private SPActionLink _manageLink;

        /// <summary>
        /// Provision Link
        /// </summary>
        private SPActionLink _provisionLink;

        /// <summary>
        /// Unprovision Link
        /// </summary>
        private SPActionLink _unprovisionLink;

        /// <summary>
        /// Roles
        /// </summary>
        private ICollection<string> _roles;

        /// <summary>
        /// Manage Link
        /// </summary>
        public override SPActionLink ManageLink
        {
            get
            {
                if (_manageLink == null)
                {
                    _manageLink = new SPActionLink(SPActionLinkType.None);
                }
                return _manageLink;
            }
        }

        /// <summary>
        /// Provision Link
        /// </summary>
        public override SPActionLink ProvisionLink
        {
            get
            {
                if (_provisionLink == null)
                {
                    _provisionLink = new SPActionLink(SPActionLinkType.ObjectModel);
                }
                return _provisionLink;
            }
        }

        /// <summary>
        /// Unprovision Link
        /// </summary>
        public override SPActionLink UnprovisionLink
        {
            get
            {
                if (_unprovisionLink == null)
                {
                    _unprovisionLink = new SPActionLink(SPActionLinkType.ObjectModel);
                }
                return _unprovisionLink;
            }
        }

        /// <summary>
        /// Roles
        /// </summary>
        public override ICollection<string> Roles
        {
            get
            {
                if (_roles == null)
                {
                    _roles = new string[1] { "Custom" };
                }
                return _roles;
            }
        }

        /// <summary>
        /// Empty constructor
        /// </summary>
        public JobServiceInstance() : base() { }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="server">The server</param>
        /// <param name="service">The Eos service</param>
        public JobServiceInstance(SPServer server, JobService service)
            : base(XXXServiceInstanceName, server, service)
        {
        }
Run Code Online (Sandbox Code Playgroud)

现在,在Central Admin中,转到服务器上的Operations/Services.选择所需的服务器并启动该服务.

要回答您的问题列表:1.独立于WFE部署解决方案一次.2.由于该功能是场范围的,因此应在Central Admin中激活.3. SPJobLockType是SPJobLockType.Job

这并不是您想象的那样,但它的优点是可以让您轻松选择作业运行的位置,甚至在您安装该功能后很长时间(例如,如果服务器因其他内容而过载).

OnFeatureActivated方法可以更智能,如果服务存在则检查每个服务器,并在需要时添加它.但是从OnFeatureDeactivated中的每个服务中删除服务更简单.因此,如果添加新服务器,请取消激活然后重新激活该功能.