Showing posts with label jobs. Show all posts
Showing posts with label jobs. Show all posts

Wednesday, December 6, 2017

Sitecore's Jobs.aspx Admin Page for Sitecore v6.6 to v7.1


Up until the release of Sitecore 7.2 Update-6 Sitecore was missing an out-of-the-box Jobs Viewer tool - which resulted in community developers rolling their own and sharing to the rest of us.

Here are links to some of the community-driven implementations:

https://www.geekhive.com/buzz/post/2015/04/sitecore-job-viewer/

https://briancaos.wordpress.com/2014/11/11/sitecore-job-viewer-see-what-sitecore-is-doing-behind-your-back/ 

https://marketplace.sitecore.net/en/Modules/V/View_Sitecore_Jobs.aspx 

https://sitecoreblog.marklowe.ch/2014/06/view-running-sitecore-background-jobs/ 

One feature that separated Sitecore's Jobs.aspx page from the community-driven implementations was its ability to auto-refresh and essentially view jobs running in real-time without the need for a refresh button. 

It also looked very nice! :)

I wanted to use THIS Jobs.aspx page on older versions of Sitecore I still maintained, so I started decompiling the Sitecore.Kernel, SitecoreClient, and Sitecore.ExperienceContentManagement.Administration binaries from v8.1 in an attempt to consolidate all the code into one Jobs.aspx page - no additional dll required.

Here's the result:

  <%@ Page language="c#" EnableEventValidation="false" AutoEventWireup="true" Inherits="Sitecore.sitecore.admin.AdminPage" %>   
  <script runat="server">   
   protected override void OnInit(EventArgs e)   
   {   
   base.CheckSecurity(true); //Required!   
   base.OnInit(e);   
   }   
  void Page_Load(object sender, System.EventArgs e)   
  {   
       Sitecore.Jobs.JobManager.GetJobs();   
     StringBuilder stringBuilder = new StringBuilder();   
     Type type = typeof(Sitecore.Jobs.JobManager);   
     this.ShowRefreshStatus(stringBuilder);   
     System.Reflection.FieldInfo field = type.GetField("_runningJobs", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);   
     if (field != null)   
     {   
      this.ShowJobs(stringBuilder, "Running jobs", ((Sitecore.Collections.SafeDictionary<Sitecore.Handle, Sitecore.Jobs.Job>)field.GetValue(null)).Values.ToArray<Sitecore.Jobs.Job>());   
     }   
     System.Reflection.FieldInfo fieldInfo = type.GetField("_queuedJobs", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);   
     if (fieldInfo != null)   
     {   
      this.ShowJobs(stringBuilder, "Queued jobs", ((Sitecore.Collections.JobCollection)fieldInfo.GetValue(null)).ToArray<Sitecore.Jobs.Job>());   
     }   
     System.Reflection.FieldInfo field1 = type.GetField("_finishedJobs", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);   
     if (field1 != null)   
     {   
      this.ShowJobs(stringBuilder, "Finished jobs", ((Sitecore.Collections.JobCollection)field1.GetValue(null)).Reverse<Sitecore.Jobs.Job>().ToArray<Sitecore.Jobs.Job>());   
     }   
     this.lt.Text = stringBuilder.ToString();   
  }   
  protected virtual void ShowJobs(StringBuilder stringBuilder, string name, ICollection<Sitecore.Jobs.Job> enumerable)   
    {   
     stringBuilder.AppendLine(string.Concat("<h1>", name, ":</h1><br />"));   
     if (enumerable.Count <= 0)   
     {   
      stringBuilder.AppendLine("<b>No jobs</b><br />");   
     }   
     else   
     {   
      stringBuilder.AppendLine("<table class='jobs-table'>");   
      stringBuilder.AppendLine("<thead><tr><td class='counter'>No</td><td class='add-time'>Added</td><td class='title'>Title</td><td class='progress'>Progress</td><td class='priority'>Priority</td></tr></thead>");   
      int num = 1;   
      foreach (Sitecore.Jobs.Job job in enumerable)   
      {   
       long total = job.Status.Total;   
       TimeSpan localTime = TimeSpan.Zero;   
       string str = (localTime.Hours == 0 ? string.Empty : string.Concat(localTime.Hours, "h "));   
       string str1 = (localTime.Minutes == 0 ? string.Empty : string.Concat(localTime.Minutes, "m "));   
       stringBuilder.AppendLine("<tr>");   
       stringBuilder.AppendLine(string.Concat("<td class='counter'>", num, "</td>"));   
       object[] longTimeString = new object[] { "<td class='add-time'>", null, null, null, null, null, null };   
       DateTime dateTime = job.QueueTime.ToLocalTime();   
       longTimeString[1] = dateTime.ToLongTimeString();   
       longTimeString[2] = " (";   
       longTimeString[3] = str;   
       longTimeString[4] = str1;   
       longTimeString[5] = localTime.Seconds;   
       longTimeString[6] = "s ago)</td>";   
       stringBuilder.AppendLine(string.Concat(longTimeString));   
       stringBuilder.AppendLine(string.Concat("<td class='title'>", job.Name, "</td>"));   
       StringBuilder stringBuilder1 = stringBuilder;   
       object[] processed = new object[] { "<td class='progress'>", job.Status.Processed   
              , null, null };   
       processed[2] = (total > (long)0 ? string.Concat(" of ", total) : string.Empty);   
       processed[3] = "</td>";   
       stringBuilder1.AppendLine(string.Concat(processed));   
       stringBuilder.AppendLine(string.Concat("<td class='priority'>", job.Options.Priority, "</td>"));   
       stringBuilder.AppendLine("</tr>");   
       num++;   
      }   
      stringBuilder.AppendLine("</table>");   
     }   
     stringBuilder.AppendLine("<br /><hr />");   
    }   
    protected virtual void ShowRefreshStatus(StringBuilder stringBuilder)   
    {   
     int num;   
     string str;   
     string item = base.Request.QueryString["refresh"];   
     int.TryParse(item, out num);   
     object[] objArray = new object[1];   
     DateTime now = DateTime.Now;   
     objArray[0] = now.ToString(System.Globalization.CultureInfo.InvariantCulture);   
     stringBuilder.Append(Sitecore.StringExtensions.StringExtensions.FormatWith("Last updated: {0}. ", objArray));   
     int[] numArray = new int[] { 1, 2, 5, 10, 20, 30, 60 };   
     stringBuilder.Append(string.Format("Refresh each <a href='jobs.aspx' class='refresh-link {0}'>No Refresh</a>", (num == 0 ? "refresh-selected" : string.Empty)));   
     int[] numArray1 = numArray;   
     for (int i = 0; i < (int)numArray1.Length; i++)   
     {   
      int num1 = numArray1[i];   
      str = (num == num1 ? "refresh-selected" : string.Empty);   
      string str1 = string.Format(", <a href='jobs.aspx?refresh={0}' class='refresh-link {1}'>{0} sec</a>", num1, str);   
      stringBuilder.Append(str1);   
     }   
     stringBuilder.Append("<br /><br />");   
    }   
  </script>    
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >   
  <html xmlns="http://www.w3.org/1999/xhtml">   
   <head runat="server">   
    <title>Jobs Viewer</title>   
    <link rel="Stylesheet" type="text/css" href="/sitecore/shell/themes/standard/default/WebFramework.css" />   
    <link rel="Stylesheet" type="text/css" href="./default.css" />   
    <style type="text/css">   
     .jobs-table {   
      border: solid 1px grey;    
      border-spacing: 2px;   
      border-collapse: separate;   
      width: 100%;   
     }   
     .jobs-table td {   
      padding: 2px;   
     }   
     .jobs-table thead {   
      font-weight: bold;   
     }   
     .jobs-table .counter {   
      width: 25px;   
      text-align: right;   
     }     
     .jobs-table .add-time {   
      width: 150px;   
     }     
     .jobs-table .title {   
      word-break: break-all;   
     }    
     .jobs-table .progress {   
      width: 50px;   
      text-align: center;   
     }    
     .jobs-table .priority {   
      width: 80px;   
     }        
    </style>   
   </head>   
   <body>   
    <form id="Form1" runat="server" class="wf-container">   
     <div class="wf-content">   
      <h1>   
       <a href="/sitecore/admin/">Administration Tools</a> - Jobs Viewer   
      </h1>   
      <br />   
      <asp:Literal runat="server" ID="lt"></asp:Literal>   
      <script type="text/javascript">   
       function getQueryString() {   
        var result = {}, queryString = location.search.substring(1), re = /([^&=]+)=([^&]*)/g, m;   
        while (m = re.exec(queryString)) {   
         result[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);   
        }   
        return result;   
       }   
       var str = getQueryString()["refresh"];   
       if (str != undefined) {   
        c = parseInt(str) * 1000;   
        setTimeout("document.location.href = document.location.href;", c);   
       }   
      </script>   
     </div>   
    </form>   
   </body>   
  </html>   

Here is the Sitecore's Jobs Viewer admin tool working on a clean Sitecore 7.0 site:


Simply copy the code above into a new Jobs.aspx file and drop it into your site's /sitecore/admin folder.

I've confirmed this working on versions as far back as Sitecore versions 6.6.

Enjoy!