I need to generate a unique sequence number from multiple threads. I created the simple class below and it seems to work, but I'm not certain if I can rely on the sequence number being unique.
In addition, I need to be able to have the number go back to 0 if it exceeds 999999. I don't expect it to roll over for a very long time as the method will likely be called less than 100 times per day. I know that the system will be shut down periodically for maintenance before it has a chance to reach 999999.
The GetSequenceNumber
method will be called from an xslt transformation in a BizTalk map and the method could be called more than once at the same time (within the same BizTalk host instance).
On my dev system, it seems to work correctly and generates different values even if BizTalk is calling the method more than once at the same time. The dev system only has a single BizTalk host instance running.
On the production system, however, there are two servers. Am I right in thinking that this method cannot guarantee uniqueness across servers since they are running in different App Domains?
I can't use a guid because the sequence number is limited to 16 characters.
public class HelperMethods
{
private static int sequenceNumber = 0;
public string GetSequenceNumber()
{
string result = null;
int seqNo = Interlocked.Increment(ref sequenceNumber);
result = string.Format("{0:MMddHHmmss}{1:000000}", DateTime.Now, seqNo);
return result;
}
}
I thought that I might be able to use the servers computer name and prepend some arbitrary character so that even if the sequence number generated on one server was the same as the other, it would still be different, but I'm not sure how unique it would be. Something like this:
string seqNumber = (MachineName == "Blah" ? "A" : "B") + GetSequenceNumber();
Does anyone have any suggestions as to how I can create a unique sequence number? It doesn't have to be perfectly unique, I just need collisions to be very unlikely. Also, how can I reset the number back to 0 if it reaches 1000000 in a thread safe way?
This should do a fairly good job of returning a unique string of 16 characters. It's based on a Guid
being unique. Since a Guid
converts to a 24 character string when using Convert.ToBase64String
it folds the bytes over itself using an XOR to ensure that the uniqueness is spread throughout the 16 characters needed.
Guid gd = Guid.NewGuid();
byte[] ba = gd.ToByteArray();
ba = ba.Zip(ba.Reverse(), (b0, b1) => (byte)(b0 ^ b1)).ToArray();
string mostLikelyUnique16 = Convert.ToBase64String(ba).Substring(0, 16);
I get results like 8QBIi7JpCeHhCWmy
.
There's no guarantee of uniqueness, but I would think it'd be fairly good, especially given your requirements allowing for occasional collisions.
I did a simple test and produced 1 million values without any collision.
If number of servers is known in advance and not very large then you could assign most significant digits to a "server ID", that is set in configuration for each server. So for instance in set of 10 servers one of them could only work with numbers in range 3000000-3999999. For another instance in a set of 100 servers it would be a range 4200000-4299999.
Main thing is to have in configuration the information that tells servers apart.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With