ehosmer,
Could you give us an overview of the custom action and specifically what is happening? Without much information, my best guess is that the files are running all at the same time, because the Run command usually spawns the app (or MSI in this case) and then moves on.
If that is the case, then you might want to have a loop in between Run calls to check for specific files installed by each MSI:
/* pseudocode */
Run "msi1"
while not (FileExists("sentinelfilename"))
[do nothing]
Run "msi2"
This will prevent the second MSI from being run until the first is done.
You could also do something like use 3 custom actions, or use MessageBoxes to stop the program from continuing until the MSI is fully installed, then clear the MessageBox and run the next MSI.
Hope this helps, if not, then let me know a bit more about what sort of issues you're running into.