A Meaty Problem
"The scales are down again, where the heck is Andre?"
Roger had heard this cry often enough that he didn't bother to poke his head out of his cubicle to see what the issue was. He worked for a meat-packing company. Sides of beef came in one side of the building, where they were sectioned and cut into smaller, grocery-store-friendly portions, and then shipped out the other side in refrigerated trucks. Along the way, the pieces of meat needed to be weighed multiple times. When the scales went down, production stopped.
"I've got it," Andre called out. "They'll be back up in a second!"
The scales weren't Roger's job. His job was making sure bills of lading and manifests and shipping instructions could be generated for every truck going out. That system was fragile and provided him more than enough work- he needed to integrate data from three different off-the-shelf ERPs and generate output suitable for each of their shipping partners (who all required different formats). Roger had enough problems without worrying about Andre's scales.
But damn, if those scales didn't go down a lot.
After a bad stretch of frequent outages, Pierre, the plant manager, had enough. Furious, he called the entire IT department into a conference room to give them a dressing down. He had a slide deck with charts and graphs documenting each of the IT failures that had impacted meat packing. "We pack and ship meat," Pierre said as he paced in front of the projector screen. "This company's been doing that since before you had this newfangled computer garbage, and we'll keep doing it when computers get replaced by robots or whatever. All I want to know is, why are you screwing up my goddamn plant?"
No one made it out of the meeting unscathed. Roger got called out because an outdated template file caused a shipping label misprint which left a truck sitting in the dock for two hours. There was one system, though, that represented the lion's share of the issues on the graphs: Andre's scale management system.
After the meeting, Roger's boss, Elene, pulled him aside. "Andre is really struggling," she said. "And he says it's an issue with communicating. Can you give him a hand?"
Roger said "yes", and sat down with Andre. "So," he said, "you always seem to be able to fix the problem pretty quickly. What's the underlying cause?"
"Oh, well," Andre said, "this cruddy scale system is like three hundred years old, and like anything built in the mainframe era, it only understands flat-file format instructions. To get data from our database and into the weighing system, I have to send it a file. Sometimes, there's a locking issue, and I can fix it by just deleting the file."
"That would be annoying," Roger said. "So you have to delete the file and resend it?"
"Well, it's not usually the file we send that gets locked. It's usually the INI file."
"The" can I see your code?"
Roger traced through the code, starting with the function that fetched data from the database. FindProductInfo was a pretty standard CRUD function, so he looked for places where it was called- like UpdateData.
private static void UpdateData(string Data){ MyProduct currentProduct; if (!FindProductInfo(Data.Split('|')[2].Trim(), out currentProduct)) { // Data reading error ? Log("Error while reading data or while accessing database"); return; } // Saving data IniHelper.WriteVariable("", "Input.ini", "Input", "Id", currentProduct.Id); IniHelper.WriteVariable("", "Input.ini", "Input", "Description", currentProduct.Description); IniHelper.WriteVariable("", "Input.ini", "Input", "GTIN_ProduitFini", currentProduct.GTIN); IniHelper.WriteVariable("", "Input.ini", "Input", "UnitPrice", currentProduct.UnitPrice.ToString()); IniHelper.WriteVariable("", "Input.ini", "Input", "Components", currentProduct.Components); IniHelper.WriteVariable("", "Input.ini", "Input", "Complementary information", currentProduct.Complementary information); IniHelper.WriteVariable("", "Input.ini", "Input", "EANPrefix", currentProduct.EANPrefix); IniHelper.WriteVariable("", "Input.ini", "Input", "WeightType", currentProduct.WeightType.ToString()); IniHelper.WriteVariable("", "Input.ini", "Input", "Weight", currentProduct.Weight.ToString()); IniHelper.WriteVariable("", "Input.ini", "Input", "Tare", currentProduct.Tare); IniHelper.WriteVariable("", "Input.ini", "Input", "FlagModif", "1");}
"So" you read the product out of the database and then write all of its details into an INI file? Is that the 'flat file' you're sending over to the weighing system?"
"No," Andre said. "They have their own weird format. I guess it's not technically a flat file, but whatever you call it. There's a template we fill in."
Roger shook his head. "I don't think we're talking the same language. Why are you writing this to an INI file?"
"Because that b-" Andre caught himself and glanced around the cube-farm. In a whisper, he said, "Because Elene said I'm not allowed to use global variables, even when they totally make sense. This was the easiest way I could come up with to pass product details to the SendVariablesToScale function."
Terrified, Roger pulled up that function.
public static void SendVariablesToScale(){ string GTIN ; string BATCH ; string UBD ; string Description ; string UnitPrice ; string Components ; string Birth ; string Breeding ; string Felling ; string Carving ; string Category ; string Type ; string InfoComplementaires ; string EANPrefix ; string WeightType ; string Tare ; // Reading current data IniHelper.ReadVariable("", "Input.ini", "Input", "EndProduct_GTIN", out GTIN); IniHelper.ReadVariable("", "Input.ini", "Input", "BATCH", out BATCH); IniHelper.ReadVariable("", "Input.ini", "Input", "DLC", out DLC); IniHelper.ReadVariable("", "Input.ini", "Input", "Description", out Description); IniHelper.ReadVariable("", "Input.ini", "Input", "UnitPrice", out UnitPrice); IniHelper.ReadVariable("", "Input.ini", "Input", "Components", out Components); IniHelper.ReadVariable("", "Input.ini", "Input", "Birth", out Birth); IniHelper.ReadVariable("", "Input.ini", "Input", "Breeding", out Breeding); IniHelper.ReadVariable("", "Input.ini", "Input", "Felling", out Felling); IniHelper.ReadVariable("", "Input.ini", "Input", "Carving", out Carving); IniHelper.ReadVariable("", "Input.ini", "Input", "Category", out Category); IniHelper.ReadVariable("", "Input.ini", "Input", "Type", out Type); IniHelper.ReadVariable("", "Input.ini", "Input", "Complementary information", out InfoComplementaires); IniHelper.ReadVariable("", "Input.ini", "Input", "EANPrefix", out EANPrefix); IniHelper.ReadVariable("", "Input.ini", "Input", "WeightType", out WeightType); IniHelper.ReadVariable("", "Input.ini", "Input", "Tare", out Tare); // Sending the vars to the weighing system // We need to send the file in the import folder try { string Buf = File.ReadAllText(Application.StartupPath + "\\myTemplateFile.txt", Encoding.Default); Buf = Buf.Replace("<GTIN>", GTIN); Buf = Buf.Replace("<BATCH>", BATCH); Buf = Buf.Replace("<UBD>", UBD); Buf = Buf.Replace("<Description>", Description); Buf = Buf.Replace("<UnitPrice>", UnitPrice); Buf = Buf.Replace("<Components>", Components); Buf = Buf.Replace("<Birth>", Birth); Buf = Buf.Replace("<Breeding>", Breeding); Buf = Buf.Replace("<Felling>", Felling); Buf = Buf.Replace("<Carving>", Carving); Buf = Buf.Replace("<Category>", Category); Buf = Buf.Replace("<Type>", Type); Buf = Buf.Replace("<Complementary information>", Complementary information); Buf = Buf.Replace("<EANPrefix>", EANPrefix); Buf = Buf.Replace("<WeightType>", WeightType); Buf = Buf.Replace("<Tare>", Tare); MyMutex.WaitOne(); File.AppendAllText(outputFolder + "BufferOutput.tmp", "\r\n" + Buf, Encoding.Default); MyMutex.ReleaseMutex(); } catch (Exception E) { Log("EXCEPTION", "Unable to send data !"); Log("(NEXT)", E.Message); }}
"See?" Andre said. "It's the BuffeerOutput.tmp file that we actually send to the scale system, but input.ini is the one that usually locks us up."
"Well," Roger said, looking straight at Andre. "I think I see the problem."
[Advertisement] Onsite, remote, bare-metal or cloud - create, configure and orchestrate 1,000s of servers, all from the same dashboard while continually monitoring for drift and allowing for instantaneous remediation. Download Otter today!