/// <summary>
        /// Called to find(or create if one is not found) the appropriate OutboundSessionDriver for a given partition.
        /// This method will ensure that we have a one(targetPartition)-to-one(outBoundSessionDriver) relationship.
        ///
        /// TODO: this layer must catch all exceptions and decide what to do with them -- lower layer functions like ResolveAndNormalizeTargetPartition
        /// will throw in case of unrecoverable errors like FabricObjectClosedException
        /// </summary>
        /// <param name="targetPartition">Find or Create OutBoundSessionDriver for this Partition</param>
        /// <param name="streamManager">Stream manager that manages the reference to the driver</param>
        /// <param name="sessionConnectionManager">Use this session connection manager to create a new session if one if not found</param>
        /// <param name="timeout">Timeout</param>
        /// <returns>Returns OutboundSessionDriver if successfull, null otherwise</returns>
        internal static async Task <OutboundSessionDriver> FindOrCreateDriverAsync(
            PartitionKey targetPartition,
            StreamManager streamManager,
            SessionConnectionManager sessionConnectionManager,
            TimeSpan timeout)
        {
            OutboundSessionDriver streamOutboundSessionDriver = null;
            // Complete the call within this time.
            var remainingTimeout = timeout;

            try
            {
                FabricEvents.Events.FindOrCreateOutboundSessionDriver("Start@" + streamManager.TraceType, targetPartition.ToString());
                var beforeResolve = DateTime.UtcNow;

                // The sync point pattern is used here because lock() pattern is not compatible with await pattern
                var normalizedPartitionKey = await streamManager.SessionConnectionManager.ResolveAndNormalizeTargetPartition(targetPartition, remainingTimeout);

                Diagnostics.Assert(
                    null != normalizedPartitionKey,
                    "normalizedPartitionKey is not expected to be null in OutboundSessionDriver.FindOrCreateDriverAsync().");

                // Update remaining time for timeout
                var afterResolve = DateTime.UtcNow;
                remainingTimeout = TimeoutHandler.UpdateTimeout(remainingTimeout, beforeResolve, afterResolve);

                var syncPoint
                    = new SyncPoint <PartitionKey>(
                          streamManager,
                          normalizedPartitionKey,
                          streamManager.RuntimeResources.OutboundSessionDriverSyncpoints);

                try
                {
                    // this is entering an await compatible critical section -- syncPoint.Dispose will leave it
                    await syncPoint.EnterAsync(remainingTimeout);

                    var afterEnter = DateTime.UtcNow;
                    remainingTimeout = TimeoutHandler.UpdateTimeout(remainingTimeout, afterResolve, afterEnter);

                    // Check if the driver already exists
                    var exists = streamManager.RuntimeResources.OutboundSessionDrivers.TryGetValue(normalizedPartitionKey, out streamOutboundSessionDriver);

                    // TODO: should we refcount how many streams depend on this session?

                    // create a new driver if if it does not exist already
                    if (!exists)
                    {
                        FabricEvents.Events.FindOrCreateOutboundSessionDriver("Creating@" + streamManager.TraceType, normalizedPartitionKey.ToString());

                        // we are actually the first stream attaching to this partition on start or recovery or all previous ones closed

                        // Find or create a new reliable messaging session
                        var session = await sessionConnectionManager.FindOrCreateOutboundSessionAsync(normalizedPartitionKey, remainingTimeout);

                        Diagnostics.Assert(null != session, "Session is not expected to be null in OutboundSessionDriver.FindOrCreateDriverAsync().");

                        // Create a new outbound session driver
                        streamOutboundSessionDriver = new OutboundSessionDriver(normalizedPartitionKey, streamManager, sessionConnectionManager, session);
                        Diagnostics.Assert(
                            null != streamOutboundSessionDriver,
                            "Stream OutboundSessionDriver is not expected to be null in OutboundSessionDriver.FindOrCreateDriverAsync().");

                        // Add ref. to stream manager active runtime resources
                        var addSuccess = streamManager.RuntimeResources.OutboundSessionDrivers.TryAdd(normalizedPartitionKey, streamOutboundSessionDriver);
                        Diagnostics.Assert(
                            addSuccess,
                            "{0} Unexpected failure to add newSessionDriver in OutboundSessionDriver.FindOrCreateDriverAsync",
                            streamManager.Tracer);
                    }
                    else
                    {
                        FabricEvents.Events.FindOrCreateOutboundSessionDriver("Found@" + streamManager.TraceType, normalizedPartitionKey.ToString());
                    }
                }
                finally
                {
                    syncPoint.Dispose();
                }
                FabricEvents.Events.FindOrCreateOutboundSessionDriver("Finish@" + streamManager.TraceType, normalizedPartitionKey.ToString());
            }
            catch (TimeoutException)
            {
                FabricEvents.Events.FindOrCreateOutboundSessionDriver("Timeout@" + streamManager.TraceType, targetPartition.ToString());
                throw;
            }
            catch (Exception e)
            {
                Tracing.WriteExceptionAsWarning("FindOrCreateDriverAsync.Failure", e, "{0}", streamManager.Tracer);
                throw;
            }

            return(streamOutboundSessionDriver);
        }