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

时间:2010-06-01 21:45:11

标签: sharepoint sharepoint-2007 sharepoint-2010 timer-jobs

我有一个计时器工作,我想每天只运行一次,用于整个农场。我如何

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

1 个答案:

答案 0 :(得分: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>

事件接收者内部:

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

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

关于子类的更多细节:

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) { }

...

当然还有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)
        {
        }

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

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

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

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