The Update Set Merging versus Batching Debate

Have you ever run a deployment where the system seemed to hang for the longest time?

The reason it appears to hang is most likely due to changes to a table’s structure in the database.

Any change to a table’s structure requires the database to make a shadow copy of that database table. The database then copies the existing data from the original table to the new table, drops the original table and then renames the shadow table to the original name.

That’s a lot of disk activity, especially when we’re working with wide tables (many columns) and rows. I have two tables that immediately come into mind here, task and cmdb_ci.

Take two update sets. The first one adds a column to a wide and deep table, the second removes that column.

Scenario 1 – Batched update sets.
The developer creates an update set, let’s call it “US-A”. They add a column to the task table, add some other objects, and then decide to test their update so they complete it and migrate to Test. Let’s assume that deployment takes 5 minutes.

They later realize that they don’t need that column, or that it belongs in an extended table. They create Update Set B (“US-B”) and remove the column. They then deploy that to the Test environment to test it.

Hypothetical Total Transaction Time: 5 minutes to add the column to task, 5 minutes to remove that column from task (it’s actually more). So we are looking at roughly 12 minutes to fully execute both update sets.

With batched update sets, this scenario will play out in all future migrations. The system will execute US-A and then US-B at a cost of 12 or more minutes.

Scenario 2 – Merged update sets.
Same thing as scenario 1, except the create column action is now merged or overwritten by the remove column operation. During the migration the system will look for that column to remove it, realize that it doesn’t exist and ignore the operation. The total cost in this case is at most, one second? You are also saving yourself a lot of unnecessary disk I/O. Less moving parts, less potential for issues.

Since we only have one update set to move that functionality, there is less overhead for the release manager and less potential to miss something.

I am of the opinion that batched update sets do have a role, but that role is limited. I could see them being used to create parent-child relationships between releases. If we set R(N+1) as a child of R(N) then for any future deployment, the system will know how to correctly deploy each sequential release.

Life with Martial Arts

Just want to take a moment and share with you something that means the world to me.  I am 43 years old.  About 23 years ago I had started taking Tae-Kwon-Do classes at my local Do-Jang (School).   I ended up following that up with Hapkido and in college, Judo and Aikido.   I was doing really good, then my money ran out.  The college classes ended, and I quit the TKD studio.

I missed it.

Flash forward 20 years, I’m married now, a father of three beautiful girls, very much out of shape and overweight.  But that little voice has always been there and that desire to complete that task that I had started 20 years before.   Well,  my little girl “won” a month of classes at our local Karate school.   They took classes and I couldn’t help but notice how much fun they were having.   In that school, Dad’s are free in January.

So here I go, 40 years old, 300+ lbs and I took my first steps.  It’s hard, it’s challenging, you cannot expect results overnight, but just keep moving.  I had equated it to a freight train when it first starts to move,  it requires so much effort.

Guess what…

Like a freight train, once it’s moving, once your moving, it gets less impossible.   Notice I didn’t say “easy”.  It never gets “easy”.  But you start to realize that, hey, YOU can do this.

Whether your 6 years old or 60, don’t give up on yourself.  Starting to move is the hardest thing you’ll ever do.

Flash forward 3 years to today.  Next month, I will be testing for my black belt.  My 23 year old dream is in my grasp.

Martial Arts for me is a huge stress relief.  In the right school, you’ll find out quickly, it’s not about hurting others, it’s about lifting each other up.   It’s about others showing you what true grit you have.

If you’re sitting there now, depressed, angry at yourself, or just feel “ugh.”  Do some research, find the right school and start.  Once you start, don’t ever stop…

Learn from my experience… YOU CAN DO THIS.

 

Knowledge15

I’ve had a great time at Knowledge15. There are some really cool things coming up with Geneva. ServiceWatch is taking Discovery in a new direction, and there’s definitely a trend from computers to phones and now watches. We’re being freed from the confines of our desks. AngularJS is going to save us a lot of time coding CMS front ends.
It’s truly an exciting time.

So I’m curious, if you had a magic wand and you could make one thing happen within Service-Now, what is the ONE thing you would improve?

Certified!

So, it’s official, I’m certified crazy.  Well, not quite.   I finished the Implementation Specialist Certification, a 90 minute test, in 30 minutes and passed!  Now I’m officially a Certified System Administrator as well as Implementation Specialist.

I have to plug my place of employment.  I get to work with a small group of really intelligent gentlemen who just kick butt with Service-Now.  

If you have any admin or implementation needs, check us out.  http://www.crossfuze.com.

 

Cleaning Up Email Responses

Here is a cool trick I developed at some point.

This strips out the inline appendage most email systems put at the end of a reply, so all you get is the update, makes the work log much cleaner and easier to read…


gs.include('validators');

if (current.getTableName() == "incident") {

var body = email.body_text;

// Look for the 'From: System Email' tag, so we can strip off the chain.
// The -6 is added to remove the “From: “ portion of the message.
var beginInbound = body.indexOf(gs.getProperty("glide.email.username")) - 6;

if(beginInbound >= 0) {
// Strip off the original message and trim the whitespace.
body = body.substring(0, beginInbound).trim();
}

current.comments = "reply from: " + email.origemail + "\n\n" + body;
current.work_notes = "Inbound Email Response from " + email.origemail;

current.update();
}

The Session Stack

Many, many thanks to Chris Czerniak and Orlando Carattini at Service-Now for this one.

One of the really handy features of Web Servers is the ability to take a value and place it into memory.
The value is then maintained in memory for the life-cycle of the request, session or application.

So how does this play into Sevice-Now?

First a little history. My company has a lot of integration with various systems. To assist the business process, we expose “external links” in the left-hand nav menu through Service-Now for these integrations.

We are a MSP of MSPs. We brand our services for our customers. One aspect of this branding is showing the customers of our customers a unique view to Service-Now and these external systems.

This branding is done via URL, so the menus within Service-Now need to point to a different URL for each MSP we service.

We originally wrote a function in a script include that looked up the user’s company and domain and returned the url for that domain. The problem with this is each menu item rendered sucks up about 0.7 seconds to make the call to the function, do the various queries and return a result. There are 16 menu items, so it took about 11.2 seconds to render the external menus alone.

Here’s where this next tid-bit comes in handy, the user preference stack.

When you log into the system, your user preferences are stored in the session stack.
This is the object that is returned by gs.getUser() in your scripts.

The interesting thing about this object is that it can be manipulated.

Here is a sample script for user preferences. You can test it in scripts background.

//set a preference for current session id
gs.getUser().setPreference("test","hello Current User");
gs.print(gs.getPreference("test"));

Now back to my dilemma. 11.2 seconds is a terrible experience to the users of the system.
I needed to make the screen load faster. Since the value returned from the function was the same for each menu, it made sense to put that value in memory on the first run then just pull it from memory for each subsequent runs.

Wouldn’t you know, I took that load time from 11.2 seconds, down to 2 seconds.

Killing Rogue Sessions

Audience:
System Administrators

How to do it:
In QuickNav type in ‘Active Sessions’. This option may not be available in some systems.

Check the session you want to kill. In the list drop down menu, select ‘Kill”.

Uses:

This can be helpful terminating sessions that are taking longer than expected or are causing undesirable results.

Disclaimer:
These tips and tricks are to give you more power to handle the tasks that you may face developing and maintaining the Service-Now application. Use them at our own risk, and by all means use them in a “sand box” environment first. With great power, comes great responsibility.

Managing Email Replies

I actually did this a while ago for our email system, but I think it’s something that can be used often as we manage email replies to our tickets.

Email systems such as Microsoft’s Outlook like to append the original message to the bottom of the reply so that we, as users can recall what the original message is about. It makes perfect sense from a human perspective. However, when we’re recording the reply to a message inside a work log, it can get pretty ugly and make the work log very difficult to read. There’s a pretty simple “fix” for this in Service-Now.

Go to System Policy -> Inbound Actions in the Left Hand Nav.

System Properties -> Inbound Email Actions

Take a look at one of the existing Update scripts. For this example, I’ll borrow the Inbound Action script from the Service-Now Demo site.

gs.include('validators');

if (current.getTableName() == "incident") {
  current.comments = "reply from: " + 
        email.origemail + "\n\n" + email.body_text;

  if (email.body.assign != undefined)
    current.assigned_to = email.body.assign;

  if (email.body.priority != undefined && 
                   isNumeric(email.body.priority))
    current.priority = email.body.priority;

  if (email.body.category != undefined)
    current.category = email.body.category;

  if (email.body.short_description != undefined)
    current.short_description = email.body.short_description;

  current.update();
}

It’s pretty straight forward, includes some validators, verifies the email is intended for the Incident table, and start to format a comment to be saved against the target ticket.

Here’s where the magic needs to happen. Out of the box, it just grabs the entire reply and stores it in the comment field. We want to make it a little smarter by trimming the string at the point of the original message, but we want to do it as intelligently as possible.

  if (current.getTableName() == "incident") {
    
    var body = email.body_text;
    
    /*
     * The name of the sender of the message is stored in a property
     * called glide.email.username. We want to leverage this when
     * we strip off the original message.
    **/
    var system_user_name = gs.getProperty("glide.email.username");

    /*
     * Now look for the 'From: <System Email>' tag, so we can strip
     * off the chain.  ( ['F', 'r', 'o', 'm',':', ' '] = 6 )
    **/ 
    var beginInbound = body.indexOf(system_user_name) - 6;
    
    if(beginInbound >= 0) {
      // Strip off the original message
      body = body.substring(0, beginInbound).trim();
    }

    /*  Other Actions Here */

    current.comments   = 
               "reply from: " + email.origemail + "\n\n" + body;
    current.work_notes = 
               "Inbound Email Response from " + email.origemail;

    current.update();

One thing to watch out for, some clients will put the original message at the top. This message would strip off the reply. I’m sure there are other, better ways of doing this, but it’s worked for me.

Tales from the “Geek Side”

Okay this has nothing to do with Service-Now, but I have to share it.

I’ve never been a fan of Mac’s. Just not a gaming platform, but I decided to take a chance and had my Intel laptop replaced with a Mac when they offered them up at work. A couple of days ago, I lost my magic mouse. I had no idea how dependent I had become on this thing, until I lost it. It was driving me nuts! It’s just “the icing on the cake” with Lion.

So I’m sitting here this morning, and it’s taunting me. I’m receiving “connected”, “not connected” messages now and then. So, that’s it, GAME ON, I’m finding the damn mouse.

Google to the rescue, “help me find my bluetooth mouse”.

Turns out Apple has a pretty cool feature, you bring up your System Preferences –> Bluetooth menu, highlight your lost device and hit the option key, it’ll tell you the signal strength of your device… the lower the number the weaker the signal.

So, I grab the laptop, start covering my house. When I lost connection I knew I was getting “colder”. Turn around, wait for the signal and continue my search. The last place I remember having it was either at my table, or on my couch. I had searched both of these places in the past to no avail.

I proceed to my kitchen table, -80, very weak signal, can’t be here.

Start moving over to the couch, -75, -64, -60… It HAS to be here.

Completely tear apart the couch, and voila! One recovered mouse.

Sometimes, I just LOVE being a geek, and yes.. Apple has won me over.