/** * Put a record asynchronously. A {@link ListenableFuture} is returned that * can be used to retrieve the result, either by polling or by registering a * callback. * * <p> * The return value can be disregarded if you do not wish to process the * result. Under the covers, the KPL will automatically reattempt puts in * case of transient errors (including throttling). A failed result is * generally returned only if an irrecoverable error is detected (e.g. * trying to put to a stream that doesn't exist), or if the record expires. * * <p> * <b>Thread safe.</b> * * <p> * To add a listener to the future: * <p> * <code> * ListenableFuture<PutRecordResult> f = myKinesisProducer.addUserRecord(...); * com.google.common.util.concurrent.Futures.addCallback(f, callback, executor); * </code> * <p> * where <code>callback</code> is an instance of * {@link com.google.common.util.concurrent.FutureCallback} and * <code>executor</code> is an instance of * {@link java.util.concurrent.Executor}. * <p> * <b>Important:</b> * <p> * If long-running tasks are performed in the callbacks, it is recommended * that a custom executor be provided when registering callbacks to ensure * that there are enough threads to achieve the desired level of * parallelism. By default, the KPL will use an internal thread pool to * execute callbacks, but this pool may not have a sufficient number of * threads if a large number is desired. * <p> * Another option would be to hand the result off to a different component * for processing and keep the callback routine fast. * * @param stream * Stream to put to. * @param partitionKey * Partition key. Length must be at least one, and at most 256 * (inclusive). * @param explicitHashKey * The hash value used to explicitly determine the shard the data * record is assigned to by overriding the partition key hash. * Must be a valid string representation of a positive integer * with value between 0 and <tt>2^128 - 1</tt> (inclusive). * @param data * Binary data of the record. Maximum size 1MiB. * @return A future for the result of the put. * @throws IllegalArgumentException * if input does not meet stated constraints * @throws DaemonException * if the child process is dead * @see ListenableFuture * @see UserRecordResult * @see KinesisProducerConfiguration#setRecordTtl(long) * @see UserRecordFailedException */ public TaskCompletionSource <KPLDotNetResult> AddUserRecord(string stream, string partitionKey, string explicitHashKey, MemoryStream data) { if (stream == null) { throw new ArgumentException("Stream name cannot be null"); } stream = stream.Trim(); if (stream.Length == 0) { throw new ArgumentException("Stream name cannot be empty"); } if (partitionKey == null) { throw new ArgumentException("partitionKey cannot be null"); } if (partitionKey.Length < 1 || partitionKey.Length > 256) { throw new ArgumentException("Invalid parition key. Length must be at least 1 and at most 256, got " + partitionKey.Length); } try { UTF8Encoding.UTF8.GetBytes(partitionKey); } catch (Exception e) { throw new ArgumentException("Partition key must be valid UTF-8"); } BigInteger b = new BigInteger(0); if (explicitHashKey != null) { explicitHashKey = explicitHashKey.Trim(); try { b = new BigInteger(UTF8Encoding.UTF8.GetBytes(explicitHashKey)); } catch (FormatException e) { throw new ArgumentException("Invalid explicitHashKey, must be an integer, got " + explicitHashKey); } if (b != null && b.CompareTo(UINT_128_MAX) > 0 || b.CompareTo(BigInteger.Zero) < 0) { throw new ArgumentException("Invalid explicitHashKey, must be greater or equal to zero and less than or equal to (2^128 - 1), got " + explicitHashKey); } } if (data != null && data.Length > 1024 * 1024) { throw new ArgumentException("Data must be less than or equal to 1MB in size, got " + data.Length + " bytes"); } long id = Interlocked.Increment(ref messageNumber) - 1; var f = new TaskCompletionSource <KPLDotNetResult>(); futures.TryAdd(id, f); PutRecord pr = new PutRecord() { StreamName = stream, PartitionKey = partitionKey, Data = data != null?Google.Protobuf.ByteString.CopyFrom(data.ToArray()) : Google.Protobuf.ByteString.Empty }; if (!b.IsZero) { pr.ExplicitHashKey = b.ToString(); } child.add(new Message() { Id = (ulong)id, PutRecord = pr }); return(f); }
public TaskCompletionSource <UserRecordResult> AddUserRecord(string stream, string partitionKey, string explicitHashKey, byte[] data) { if (string.IsNullOrEmpty(stream)) { throw new ArgumentException("Stream name cannot be null or empty", nameof(stream)); } stream = stream.Trim(); if (stream.Length == 0) { throw new ArgumentException("Stream name cannot be empty", nameof(stream)); } if (partitionKey == null) { throw new ArgumentException("PartitionKey cannot be null", nameof(partitionKey)); } if (partitionKey.Length < 1 || partitionKey.Length > 256) { throw new ArgumentException($"Invalid parition key. Length must be at least 1 and at most 256, got {partitionKey.Length}", nameof(partitionKey)); } try { Encoding.UTF8.GetBytes(partitionKey); } catch (Exception) { throw new ArgumentException("Partition key must be valid UTF-8", nameof(partitionKey)); } BigInteger?b = null; if (explicitHashKey != null) { explicitHashKey = explicitHashKey.Trim(); try { b = BigInteger.Parse(explicitHashKey); } catch (FormatException) { throw new ArgumentException($"Invalid explicitHashKey, must be an integer, got {explicitHashKey}", nameof(explicitHashKey)); } if (b.Value.CompareTo(UINT_128_MAX) > 0 || b.Value.CompareTo(BigInteger.Zero) < 0) { throw new ArgumentException($"Invalid explicitHashKey, must be greater or equal to zero and less than or equal to (2^128 - 1), got {explicitHashKey}", nameof(explicitHashKey)); } } if (data != null && data.Length > 1024 * 1024) { throw new ArgumentException($"Data must be less than or equal to 1MB in size, got {data.Length} bytes", nameof(data)); } long id = Interlocked.Increment(ref messageNumber) - 1; var future = new FutureOperationResult(new TaskCompletionSource <UserRecordResult>()); futureOperationResults.TryAdd(id, future); var putRecord = new PutRecord { Data = data ?? new byte[0], StreamName = stream, PartitionKey = partitionKey }; if (b.HasValue) { putRecord.ExplicitHashKey = b.ToString(); } var msg = new Message { Id = (ulong)id, PutRecord = putRecord }; child.Add(msg); return(future.LeftOrDefault); }