Maximo – Configuring RoboCopy to duplicate DocLinks to a second server
Intro
IBM’s Maximo can be used to record maintenance on objects. We use it to track maintenance of items to ensure our sites are safe and fall within any nation-state regulation and our sites keep running.
Like most process systems, it has a relational database and a text search engine, it uses the SQL Server for both, and a file store which is on local storage on the application server.
Configuration
We have three servers:
- SQL Server – for the relational database and the text search engine.
- Application server – to run the main interface for the web front-end.
- Reporting server – to offload the running of the long reports.
I manage the operating systems and the management of the SQL Server, so I have a limited perspective on the system, and I see problems, but the users love the application, and it gives them a tool to complete their business tasks.
Heaps, implicit transactions & Indexes
All of the tables are heaps, they don’t have a clustered index, and the queries from the server use implicit transactions which always go single-threaded.
IBM allows you to manage your indexes so using Brent’s DEATH method (without the heap bit) I’ve trimmed the DB to not have indexes it doesn’t use. The problem is that the heaps are very wide so indexing will always be an issue.
Doclinks
Doclinks is the managed area for the file store. This area allows items like PDF items to be stored and retrieved for the users to check, the problem is that Maximo only allows local storage for the Doclinks area it can’t be on a shared storage device which is OK for the main application server but for the reporting server have access to the files they need to be replicated from the application servers local storage to the reporting servers local storage.
RoboCopy
Microsoft’s command-line RoboCopy (Robust File Copy) directory/file replication software has been around since 1996. There are probably better tools out there but as it can be installed with the standard Windows Server Operating System, it works, people know how to use it, and is from a trusted vendor we tend to use it.
Problem domain
We have a primary file store area we need to regularly synchronize with the secondary area. There tends not to be a rapid change in file store so the secondary file store can be slightly behind the primary.
Ideally, when a file is changed in the file store it should be event-driven but we are not using this method as we are going for a simpler, polling, implementation.
Task Scheduler
Using the built-in task scheduler, I configure a batch script to run the RoboCopy tool. With feedback from the users, they felt that they wouldn’t want the reporting file store to be out of date by more than thirty minutes.
The RoboCopy application is relatively lightweight and quick to run especially if it is only checking to see if it needs to copy or delete a file on the secondary file store.
Problems
Initially, I set up the task with a simple one-liner which seemed to work but occasionally I received feedback about files not copying over. The implementation wasn’t good enough, when an application runs it should exit with an exit status to indicate how successful it was. I also want to create a log so if there was an issue, I would have something to look at instead of looking dumb.
I found a great site with information about creating an error-handling batch file at ss64.com. This enables the management of the exit status from RoboCopy and I also added a log file to be created over the last log file each time. I know this is a crude solution but so far it seems to have worked or I would have to implement a rolling log process.
Solution
I am not sure if the changes I made fixed the issue but running RoboCopy more frequently seemed to resolve the issue and the user base is happy with the solution.
rem -- Run robocopy robocopy L:doclinks <<your destination server>>L$doclinks /MIR /Z /LOG:C:robocopy_scriptrobocopy_last_log.txt rem -- report on exit status if %ERRORLEVEL% EQU 16 echo ***FATAL ERROR*** & goto end if %ERRORLEVEL% EQU 15 echo OKCOPY + FAIL + MISMATCHES + XTRA & goto end if %ERRORLEVEL% EQU 14 echo FAIL + MISMATCHES + XTRA & goto end if %ERRORLEVEL% EQU 13 echo OKCOPY + FAIL + MISMATCHES & goto end if %ERRORLEVEL% EQU 12 echo FAIL + MISMATCHES& goto end if %ERRORLEVEL% EQU 11 echo OKCOPY + FAIL + XTRA & goto end if %ERRORLEVEL% EQU 10 echo FAIL + XTRA & goto end if %ERRORLEVEL% EQU 9 echo OKCOPY + FAIL & goto end if %ERRORLEVEL% EQU 8 echo FAIL & goto end if %ERRORLEVEL% EQU 7 echo OKCOPY + MISMATCHES + XTRA & goto end if %ERRORLEVEL% EQU 6 echo MISMATCHES + XTRA & goto end if %ERRORLEVEL% EQU 5 echo OKCOPY + MISMATCHES & goto end if %ERRORLEVEL% EQU 4 echo MISMATCHES & goto end if %ERRORLEVEL% EQU 3 echo OKCOPY + XTRA & goto end if %ERRORLEVEL% EQU 2 echo XTRA & goto end if %ERRORLEVEL% EQU 1 echo OKCOPY & goto end if %ERRORLEVEL% EQU 0 echo No Change & goto end :end if %ERRORLEVEL% EQU 1 exit 0 exit %ERRORLEVEL% REM https://social.technet.microsoft.com/wiki/contents/articles/1073.robocopy-and-a-few-examples.asp REM The following command will mirror the directories using Robocopy: Rem Robocopy F:inetpubwwwroot <server>\d$inetpubwwwroot /MIR /FFT /Z /XA:H /W:5 REM Robocopy SourceServerShare DestinationServerShare /MIR /FFT /Z /XA:H /W:5 REM Explanation of the switches used: REM /MIR specifies that Robocopy should mirror the source directory and the destination directory. Note that this will delete files at the destination if they were deleted at the source. REM /FFT uses fat file timing instead of NTFS. This means the granularity is a bit less precise. For across-network share operations this seems to be much more reliable - just do not rely on the file timings to be completely precise to the second. REM /Z ensures Robocopy can resume the transfer of a large file in mid-file instead of restarting. REM /XA:H makes Robocopy ignore hidden files, usually these will be system files that we're not interested in. REM /W:5 reduces the wait time between failures to 5 seconds instead of the 30 second default.
Below are the screenshots of the ‘Task’ I created in the ‘Task Scheduler’:

Task Scheduler - General

Task Scheduler - Tridggers

Task Scheduler - Actions

Task Scheduler - Conditions

Task Scheduler - Settings

Task Scheduler History
Task Scheduler – Task
If you save a task from the Task Scheduler it produces the XML similar to the file below:
<?xml version="1.0" encoding="UTF-16"?> <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> <RegistrationInfo> <Date>2021-03-10T16:02:15.4687623</Date> <!-- add a valid domain and admin account for your server --> <Author>**your domain****an admin account**</Author> <Description>The doclinks area is used for the files store for Maximo so this needs to be replicated to the report server.</Description> </RegistrationInfo> <Triggers> <CalendarTrigger> <StartBoundary>2021-03-10T00:00:00</StartBoundary> <Enabled>true</Enabled> <ScheduleByDay> <DaysInterval>1</DaysInterval> </ScheduleByDay> </CalendarTrigger> </Triggers> <Principals> <Principal id="Author"> <!-- add a valid domain and admin account for your server --> <Author>**your domain****an admin account**</Author> <LogonType>Password</LogonType> <RunLevel>HighestAvailable</RunLevel> </Principal> </Principals> <Settings> <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy> <DisallowStartIfOnBatteries>true</DisallowStartIfOnBatteries> <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries> <AllowHardTerminate>true</AllowHardTerminate> <StartWhenAvailable>false</StartWhenAvailable> <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable> <IdleSettings> <StopOnIdleEnd>true</StopOnIdleEnd> <RestartOnIdle>false</RestartOnIdle> </IdleSettings> <AllowStartOnDemand>true</AllowStartOnDemand> <Enabled>true</Enabled> <Hidden>false</Hidden> <RunOnlyIfIdle>false</RunOnlyIfIdle> <WakeToRun>false</WakeToRun> <ExecutionTimeLimit>P1D</ExecutionTimeLimit> <Priority>7</Priority> </Settings> <Actions Context="Author"> <Exec> <!-- The location of the RoboCopy batch script --> <Command>C:robocopy_scriptrobocopy_doclinks_to_report_server.bat</Command> </Exec> </Actions> </Task>
Log file
If you are generating a log file from Robocopy is should looks something like the one below but I have removed some of the data…
------------------------------------------------------------------------------- ROBOCOPY :: Robust File Copy for Windows ------------------------------------------------------------------------------- Started : 03 January 2022 19:00:00 Source : L:doclinks Dest : <<server name removed >>L$doclinks Files : *.* Options : *.* /S /E /DCOPY:DA /COPY:DAT /PURGE /MIR /Z /R:1000000 /W:30 ------------------------------------------------------------------------------ 12425 L:doclinks 41944 L:doclinksAttached 163297 L:doclinksattachments 0 L:doclinksCommLogDocs 0 L:doclinksCONTTEMP 2 L:doclinksdefault 0 L:doclinksdiagrams 0 L:doclinksENGDOCS 0 L:doclinksimages 17 L:doclinksIntegrity ... ------------------------------------------------------------------------------ Total Copied Skipped Mismatch FAILED Extras Dirs : 251 0 0 0 0 0 Files : 219394 0 219394 0 0 0 Bytes : 239.598 g 0 239.598 g 0 0 0 Times : 0:00:00 0:00:00 0:00:00 0:00:00 Ended : 03 January 2022 19:00:00
Text content
Github
I have saved the examples to my GitHub area RoboCopy.
GitHub is a great service to allow people to version, share and collaborate so if you can start to use it. There are also some amazing project you can access and look at the source code.