I developed a workaround but if anyone can help with the actual issue I would still be interested to know how to make the workflow only run once or even if I can, just know why it runs multiple times on a single update.
My workaround was to create a ModifiedDate and ModifiedTime field as well as UpdateDate and UpdateTime variables. The workflow sets the UpdateDate to the value of the Modified column in ShortDate format and the UpdateTime to the Modified column in the ShortTime format. I had to do this because the workflows don't run at exactly the same time they are a few seconds off, doing this eliminates the seconds in the time.
I then check if UpdateDate == ModifiedDate and UpdateTime == ModifiedTime, if not then set UpdateDate = ModifiedDate and UpdateTime = ModifiedTime. If they are already equal end the workflow.
The only issue is if you actually perform multiple updates on a single fine within a minute the workflow will only run on the first change, this is not a scenario I am likely to encounter so I am ok with this limitation.