Sunday, September 28, 2008

Metastorm BPM 7.6 and Windows Workflow part 5 - Long running workflows

OK, I want to go back to basics for this post. What is the point of Windows Workflow? Here's the first paragraph of the preface to "Essential Windows Workflow Foundation"

"Windows Workflow Foundation is a general-purpose programming framework for creating reactive programs that act in response to stimulus from external entities. The basic characteristics of reactive programs is that they pause during their execution, for unknown amounts of time, awaiting input."

I've highlighted what I consider to be the important point here. A WF workflow may lay dormant for minutes, days or weeks. In the normal world of .NET code, implementing this kind of application can be troublesome. For a start, the application may shutdown and restart before the workflow resumes, so the application needs to cope with this possibility. This means the objects must be persisted and restarted with the correct state. A simple solution like making the executing thread sleep for the required amount of time isn't going to work, in terms of robustness or scalability (imagine 1000s of these workflows being executed at the same time).

So WF helps solves this problem. Without this feature, WF is really just a different approach to producing standard .NET code, either through the designer or generating declarative XML documents to explain how the code should execute. It might well be useful in some scenarios but it isn't really a killer reason to use the technology.

BPM WF

So with that in mind I created a very simple workflow to execute from Metastorm BPM, which you can see on the left. All it does is write to a text file, wait for ten minutes, then write to the text file again.

The first thing to ensure is to set the "Microsoft Workflow timeout (secs)" registry setting to something sensible. Unfortunately setting this to zero doesn't mean no timeout, it just uses the default 120 seconds timeout. So this needs setting to something very large. This is a DWORD value with a maximum value of 4294967295, which I calculate is approximately 49710 days, that hopefully is large enough for most workflows.

Executing the workflow worked fine in this scenario. The workflow idled for 10 minutes then resumed and completed.

So the next experiment was to start the workflow, shut down the engine and then restart the engine and see what happened. I waited... and waited... Nothing. I started another workflow just in case the workflow runtime hadn't been kicked off but still nothing. So there's a bit of a problem there, particularly if you want to run long running workflows.

As an aside, if you're running your workflow asynchronously then you won't be able to use most of the activities provided for interaction with Metastorm BPM. This is a shame. In particular the RaiseFlag activity would be exceedingly useful since it could be used to signal to the parent process that the workflow had completed. As it is, you'll need to do this with the ECL activities provided, which are more complicated to configure or write your own code.

Part 1 - The basics

Part 2 - The database tables

Part 3 - Using Visual Studio

Part 4 - Using your own activities

Part 6 - State machines

Wednesday, September 24, 2008

Autosizing row heights in a WinForms DataGrid

Autosizing column widths in a WinForms DataGrid is pretty easy, if a little hacky. Although it seems that a similar technique could be used to autosize row heights, the private RowAutoResize method doesn't do what I was expecting it to do. I found some useful code here which I have adapted somewhat so that it can handle DataGrids with IList based classes as their data source. It also looks at all cells to work out the required height.

    public void AutosizeRows()
    {
      int numRows = 0;
      if (DataSource is DataTable)
      {
        numRows = ((DataTable)DataSource).Rows.Count;
      }
      else if (DataSource is IList)
      {
        CurrencyManager manager = (CurrencyManager)BindingContext[DataSource];
        numRows = manager.List.Count;
      }

      using (Graphics g = Graphics.FromHwnd(Handle))
      {
        StringFormat sf = new StringFormat(StringFormat.GenericTypographic);

        // Since DataGridRows[] is not exposed directly by the DataGrid  
        // we use reflection to hack internally to it..
        MethodInfo mi = GetType().GetMethod("get_DataGridRows",
          BindingFlags.Instance | BindingFlags.NonPublic);

        Array dgra = (Array)mi.Invoke(this, null);

        // Convert this to an ArrayList, little bit easier to deal with 
        // that way, plus we can strip out the newrow row. 
        List<object> DataGridRows = new List<object>();
        foreach (object dgrr in dgra)
        {
          if (dgrr.ToString().EndsWith("DataGridRelationshipRow"))
            DataGridRows.Add(dgrr);
        }

        int colCount = TableStyles[0].GridColumnStyles.Count;

        // Now loop through all the rows in the grid 
        for (int i = 0; i < numRows; ++i)
        {
          int maxHeight = 0;

          for (int j = 0; j < colCount; j++)
          {
            SizeF size = g.MeasureString(this[i, j].ToString(), Font, 400, sf);
            int h = Convert.ToInt32(size.Height);

            // Little extra cellpadding space 
            h = h + 8;

            maxHeight = Math.Max(h, maxHeight);
          }

          // Now we pick that row out of the DataGridRows[] Array  
          // that we have and set it's Height property to what we 
          // think it should be. 
          PropertyInfo pi = DataGridRows[i].GetType().GetProperty("Height");
          pi.SetValue(DataGridRows[i], maxHeight, null);
        }
      }
    }

Sunday, September 21, 2008

Capital boozing - the Random Pub Finder book

It used to be called vanity publishing. An aspiring author, having been rejected by all the standard publishers, would decide the problem wasn't with themselves and their work, but with the publishers who were clearly blind to the author's genius. So the only solution was to go out and get their work published themselves and sell hundreds of thousands of copies that way. Of course what generally happened was that, after paying out thousands to the vanity publisher, the author would be left with 2472 copies of their masterpiece sat in the loft, after giving out the other 28 copies to friends and family.

Things have changed, we can now all be published authors via the wonderful lulu.com. The beauty of this system is that a forest doesn't get destroyed to sate the author's vanity. Books are only produced if somebody is actually interested in them. And because they are published on demand, books can be updated and corrected quickly and easily.

So to take advantage of this system, we've taken the reviews from the Random Pub Finder and put them all together in one convenient book shaped package. I don't know about you but even with all the latest technologies for reading on a screen, I still much prefer a book. No power problems, no waiting to boot up, no random crashes.

Anyway, if you want to buy a copy, hop over to http://www.lulu.com/content/2003276. I'm still waiting for a design for the cover, but other than that it's all done.

Saturday, September 20, 2008

Turn it up to 11

11I've just noticed the volume on the BBC media player on their website goes up to 11. I assume the developer of this code is an afficionado of Spinal Tap.

I can't say I've noticed the difference in sound levels between this and other web based apps...

Tuesday, September 16, 2008

Metastorm BPM 7.6 and Windows Workflow part 4 - Using your own activities

My previous posts on Metastorm/WF integration have had a few comments, so I thought I'd follow up on them.

First up, it is possible to reference your own assemblies containing custom activities in the WF Composer, via the Options dialog that can be found on the main menu. For me this means the Composer could potentially be used by non-technical people, although the workflow designer may still be too difficult to hand over to non-techies (this isn't Metastorm's fault BTW, the design surface is all Microsoft's work).

But before I could check out this feature, I had a problem using the Composer. I haven't used it for a few weeks or months and when I tried to do almost anything I got the following error

Could not load file or assembly 'mscorcfg, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. (mscorlib) 

I suspect this is down to me uninstalling Visual Studio 2005 since I installed the WF Composer which I guess uninstalled the .NET 2.0 SDK which is required by the WF Composer. It's a shame the SDK is required, as it's a 354MB download... If it's just for the one assembly then it's flipping ridiculous.

Anyway, after installing the SDK and reinstalling the Metastorm WF bits, things started working again (the re-install may not be necessary but I uninstalled before I realised what my problem was).

OK, so I thought I'd try to use some of my own activities. My first problem was that any assembly I tried to reference produced the following error

No toolbox items found in assembly!

This was easily solved by adding the following attribute to my activity class definition

[ToolboxItem(true)]

My activities now appear in the toolbox but I'm unable to drag them onto the design surface. I guess I'm missing something in my activity class code but I don't know what. They work in Visual Studio and my own designer so I'm not sure why they fail here. Anyway, although the WF Composer is of passing interest, my main interest is using workflows authored in Visual Studio, so I'm not going to look at it too closely.

Part 1 - The basics

Part 2 - The database tables

Part 3 - Using Visual Studio

Part 5 - Long running workflows

Part 6 - State machines

Thursday, September 11, 2008

Complete rewrite - two years on

It's almost two years on since I wrote about one of my previous employers starting a complete rewrite of one of the core pieces of the their application suite. So how have things turned out? To tell you the truth I have no idea, nobody from the company will give me any useful information these days. But one thing that I am sure of, the new software hasn't been released yet. So my back of a fag packet estimate of three and half years development time isn't looking quite as daft as it may have done at the time.

Having said that, it is of course possible that the software is done and the company are just waiting for the right time to release it. I remember being blown away when I discovered that Ultimate Play The Game actually held back the release of the ground-breaking Knight Lore game so they could release the less impressive Sabre Wulf without it looking rubbish.

And if you do know anything about the progress of the software of which I'm talking then post a comment, you can do it anonymously...

Tuesday, September 09, 2008

Noel Gallagher pushed off stage

I have a theory why the North West has produced more than its fair share of great popular music over the past few years (The Beatles, Joy Division, New Order, The Smiths, Happy Mondays, British Sea Power (although Brighton try to claim them as their own), Elbow, The Fall, The Stone Roses to name but a few). It's the weather. Rain, rain and more rain. People are forced to stay in quite a lot and do something. So a lot of them decide to try their hand at music and some of them succeed. But I would never include Oasis on that list. Although their initial material was catchy, it never really reached the emotional heights that great pop music does. And their output afterwards has been absolutely awful. To be fair, "Wonderwall" could have been a beautiful song had it not been for the vocals of Liam.

Anyway, I'd pretty much forgotten about Oasis, but apparently they are still chugging along with their Beatles parodies. And now we have this wonderful video of Noel being pushed off stage by somebody. Although that's slightly humorous, the bit I love is self-styled tough guy Liam. First he tries to get away from the stage invader, then when the guy has been held down by two or three security guys, he suddenly remembers how hard he really is and walks across to "have a go" at him. I think it really shows how much of a show the whole tough guy image is...

Wednesday, September 03, 2008

How to kill the hits to your website

I went on holiday a few weeks ago. Unbeknownst to me the Random Pub Finder's database died the day I went away. With no web access I only found out on my return. A few days of emails to our ISP followed (yes we should have had a backup but we didn't; fortunately our ISP did have) and finally the site was back online. A few days after that I went off to Switzerland and what do you know, the database died again. A more paranoid person than myself might think somebody knew I was going away and did it deliberately. I'm not quite that paranoid but am obviously paranoid enough to consider it as a possibility. After the first data loss I'd done a backup, but I didn't have access to it whilst I was out of my office. Anyway, upon my return, the site was restored pretty quickly. So in all the Random Pub finder was offline for about three weeks.

Prior to the database crash, we were averaging about 300-400 visitors a day, now we are barely reaching 100. I guess the broken pages are still in the search engines' caches and who knows if and when we'll get our visitors back...