This has possibility of infinite loop when handle transaction error handleTxnError().
A transaction must be canceled if some error occurs, for exactly-once. In my opinion, it would be better to delay processing (time.Sleep) or log if cross the attempt threshold in a loop. (actually my suggestion is another business feature)
ref: #3 (comment)