packages feed

nakadi-client 0.3.0.0 → 0.4.0.0

raw patch · 26 files changed

+698/−165 lines, 26 filesdep +stmdep +waidep +warpPVP ok

version bump matches the API change (PVP)

Dependencies added: stm, wai, warp

API changes (from Hackage documentation)

+ Network.Nakadi.Config: defaultHttpBackend :: HttpBackend
+ Network.Nakadi.Config: setHttpBackend :: HttpBackend -> Config -> Config
+ Network.Nakadi.Config: setHttpErrorCallback :: HttpErrorCallback -> Config -> Config
+ Network.Nakadi.Internal.Http: AccessForbidden :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: ApplicationName :: Text -> ApplicationName
+ Network.Nakadi.Internal.Http: BadRequest :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: BatchFlushTimeout :: Int32 -> BatchFlushTimeout
+ Network.Nakadi.Internal.Http: BatchItemResponse :: Maybe EventId -> PublishingStatus -> Maybe Step -> Maybe Text -> BatchItemResponse
+ Network.Nakadi.Internal.Http: BatchNotSubmitted :: [BatchItemResponse] -> NakadiException
+ Network.Nakadi.Internal.Http: BatchPartiallySubmitted :: [BatchItemResponse] -> NakadiException
+ Network.Nakadi.Internal.Http: BatchValidationFailure :: [BatchItemResponse] -> NakadiException
+ Network.Nakadi.Internal.Http: ClientNotAuthenticated :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: CompatibilityModeCompatible :: CompatibilityMode
+ Network.Nakadi.Internal.Http: CompatibilityModeForward :: CompatibilityMode
+ Network.Nakadi.Internal.Http: CompatibilityModeNone :: CompatibilityMode
+ Network.Nakadi.Internal.Http: Config :: Request -> (Request -> IO Request) -> Manager -> ConsumeParameters -> Maybe (ByteString -> Text -> IO ()) -> Maybe StreamConnectCallback -> Maybe LogFunc -> RetryPolicyM IO -> HttpBackend -> Maybe HttpErrorCallback -> Config
+ Network.Nakadi.Internal.Http: Conflict :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: ConsumeParameters :: Maybe Int32 -> Maybe Int32 -> Maybe Int32 -> Maybe Int32 -> Maybe Int32 -> Maybe Int32 -> Maybe Text -> ConsumeParameters
+ Network.Nakadi.Internal.Http: Cursor :: PartitionName -> CursorOffset -> Cursor
+ Network.Nakadi.Internal.Http: CursorAlreadyCommitted :: CursorCommitResults -> NakadiException
+ Network.Nakadi.Internal.Http: CursorCommit :: [Cursor] -> CursorCommit
+ Network.Nakadi.Internal.Http: CursorCommitResult :: SubscriptionCursor -> CursorCommitResultType -> CursorCommitResult
+ Network.Nakadi.Internal.Http: CursorCommitResultCommitted :: CursorCommitResultType
+ Network.Nakadi.Internal.Http: CursorCommitResultOutdated :: CursorCommitResultType
+ Network.Nakadi.Internal.Http: CursorCommitResults :: [CursorCommitResult] -> CursorCommitResults
+ Network.Nakadi.Internal.Http: CursorDistanceNoResult :: NakadiException
+ Network.Nakadi.Internal.Http: CursorDistanceQuery :: Cursor -> Cursor -> CursorDistanceQuery
+ Network.Nakadi.Internal.Http: CursorDistanceResult :: Int64 -> CursorDistanceResult
+ Network.Nakadi.Internal.Http: CursorOffset :: Text -> CursorOffset
+ Network.Nakadi.Internal.Http: CursorResetInProgress :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: CursorToken :: Text -> CursorToken
+ Network.Nakadi.Internal.Http: DataChangeEvent :: a -> Metadata -> Text -> DataOp -> DataChangeEvent a
+ Network.Nakadi.Internal.Http: DataOpCreation :: DataOp
+ Network.Nakadi.Internal.Http: DataOpDeletion :: DataOp
+ Network.Nakadi.Internal.Http: DataOpSnapshot :: DataOp
+ Network.Nakadi.Internal.Http: DataOpUpdate :: DataOp
+ Network.Nakadi.Internal.Http: DeserializationFailure :: ByteString -> NakadiException
+ Network.Nakadi.Internal.Http: EnrichmentStrategyMetadata :: EnrichmentStrategy
+ Network.Nakadi.Internal.Http: Event :: a -> Metadata -> Event a
+ Network.Nakadi.Internal.Http: EventEnriched :: a -> MetadataEnriched -> EventEnriched a
+ Network.Nakadi.Internal.Http: EventId :: UUID -> EventId
+ Network.Nakadi.Internal.Http: EventStreamBatch :: Cursor -> Maybe (Vector (EventEnriched a)) -> EventStreamBatch a
+ Network.Nakadi.Internal.Http: EventType :: EventTypeName -> Maybe ApplicationName -> Maybe EventTypeCategory -> Maybe [EnrichmentStrategy] -> Maybe PartitionStrategy -> Maybe CompatibilityMode -> EventTypeSchema -> Maybe [PartitionKeyField] -> Maybe EventTypeStatistics -> Maybe EventTypeOptions -> EventType
+ Network.Nakadi.Internal.Http: EventTypeCategoryBusiness :: EventTypeCategory
+ Network.Nakadi.Internal.Http: EventTypeCategoryData :: EventTypeCategory
+ Network.Nakadi.Internal.Http: EventTypeCategoryUndefined :: EventTypeCategory
+ Network.Nakadi.Internal.Http: EventTypeName :: Text -> EventTypeName
+ Network.Nakadi.Internal.Http: EventTypeNotFound :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: EventTypeOptions :: Int64 -> EventTypeOptions
+ Network.Nakadi.Internal.Http: EventTypeSchema :: Maybe SchemaVersion -> Maybe Timestamp -> SchemaType -> Text -> EventTypeSchema
+ Network.Nakadi.Internal.Http: EventTypeSchemasResponse :: PaginationLinks -> [EventTypeSchema] -> EventTypeSchemasResponse
+ Network.Nakadi.Internal.Http: EventTypeStatistics :: Int64 -> Int64 -> Int64 -> Int64 -> EventTypeStatistics
+ Network.Nakadi.Internal.Http: FlowId :: Text -> FlowId
+ Network.Nakadi.Internal.Http: HttpBackend :: (Request -> IO (Response ByteString)) -> (Request -> Manager -> IO (Response BodyReader)) -> (Response BodyReader -> IO ()) -> HttpBackend
+ Network.Nakadi.Internal.Http: Limit :: Int64 -> Limit
+ Network.Nakadi.Internal.Http: Metadata :: EventId -> Timestamp -> Maybe [EventId] -> Maybe PartitionName -> Metadata
+ Network.Nakadi.Internal.Http: MetadataEnriched :: EventId -> EventTypeName -> Timestamp -> Timestamp -> SchemaVersion -> Maybe [EventId] -> Maybe FlowId -> Maybe PartitionName -> MetadataEnriched
+ Network.Nakadi.Internal.Http: NotFound :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: Offset :: Int64 -> Offset
+ Network.Nakadi.Internal.Http: PaginationLink :: Text -> PaginationLink
+ Network.Nakadi.Internal.Http: PaginationLinks :: Maybe PaginationLink -> Maybe PaginationLink -> PaginationLinks
+ Network.Nakadi.Internal.Http: Partition :: CursorOffset -> CursorOffset -> PartitionName -> Maybe Int64 -> Partition
+ Network.Nakadi.Internal.Http: PartitionKeyField :: Text -> PartitionKeyField
+ Network.Nakadi.Internal.Http: PartitionName :: Text -> PartitionName
+ Network.Nakadi.Internal.Http: PartitionStat :: PartitionName -> PartitionState -> Int64 -> StreamId -> PartitionStat
+ Network.Nakadi.Internal.Http: PartitionStateAssigned :: PartitionState
+ Network.Nakadi.Internal.Http: PartitionStateReassigning :: PartitionState
+ Network.Nakadi.Internal.Http: PartitionStateUnassigned :: PartitionState
+ Network.Nakadi.Internal.Http: PartitionStrategyCustom :: Text -> PartitionStrategy
+ Network.Nakadi.Internal.Http: PartitionStrategyHash :: PartitionStrategy
+ Network.Nakadi.Internal.Http: PartitionStrategyRandom :: PartitionStrategy
+ Network.Nakadi.Internal.Http: PartitionStrategyUser :: PartitionStrategy
+ Network.Nakadi.Internal.Http: Problem :: Text -> Text -> Int32 -> Maybe Text -> Maybe Text -> Maybe (HashMap Text Value) -> Problem
+ Network.Nakadi.Internal.Http: PublishingStatusAborted :: PublishingStatus
+ Network.Nakadi.Internal.Http: PublishingStatusFailed :: PublishingStatus
+ Network.Nakadi.Internal.Http: PublishingStatusSubmitted :: PublishingStatus
+ Network.Nakadi.Internal.Http: RequestModificationException :: SomeException -> NakadiException
+ Network.Nakadi.Internal.Http: SchemaTypeJson :: SchemaType
+ Network.Nakadi.Internal.Http: SchemaVersion :: Text -> SchemaVersion
+ Network.Nakadi.Internal.Http: ShiftedCursor :: PartitionName -> CursorOffset -> Int64 -> ShiftedCursor
+ Network.Nakadi.Internal.Http: StepEnriching :: Step
+ Network.Nakadi.Internal.Http: StepNone :: Step
+ Network.Nakadi.Internal.Http: StepPartitioning :: Step
+ Network.Nakadi.Internal.Http: StepPublishing :: Step
+ Network.Nakadi.Internal.Http: StepValidating :: Step
+ Network.Nakadi.Internal.Http: StreamId :: Text -> StreamId
+ Network.Nakadi.Internal.Http: StreamKeepAliveLimit :: Int32 -> StreamKeepAliveLimit
+ Network.Nakadi.Internal.Http: Subscription :: Maybe SubscriptionId -> ApplicationName -> [EventTypeName] -> Maybe Text -> Maybe Timestamp -> Maybe SubscriptionPosition -> Maybe [SubscriptionCursorWithoutToken] -> Subscription
+ Network.Nakadi.Internal.Http: SubscriptionCursor :: PartitionName -> CursorOffset -> EventTypeName -> Text -> SubscriptionCursor
+ Network.Nakadi.Internal.Http: SubscriptionCursorCommit :: [SubscriptionCursor] -> SubscriptionCursorCommit
+ Network.Nakadi.Internal.Http: SubscriptionCursorWithoutToken :: PartitionName -> CursorOffset -> EventTypeName -> SubscriptionCursorWithoutToken
+ Network.Nakadi.Internal.Http: SubscriptionEventStream :: StreamId -> SubscriptionId -> SubscriptionEventStream
+ Network.Nakadi.Internal.Http: SubscriptionEventStreamBatch :: SubscriptionCursor -> Maybe (Vector (EventEnriched a)) -> SubscriptionEventStreamBatch a
+ Network.Nakadi.Internal.Http: SubscriptionEventStreamContext :: StreamId -> SubscriptionId -> Config -> SubscriptionEventStreamContext
+ Network.Nakadi.Internal.Http: SubscriptionEventTypeStats :: EventTypeName -> [PartitionStat] -> SubscriptionEventTypeStats
+ Network.Nakadi.Internal.Http: SubscriptionEventTypeStatsResult :: [SubscriptionEventTypeStats] -> SubscriptionEventTypeStatsResult
+ Network.Nakadi.Internal.Http: SubscriptionExistsAlready :: Subscription -> NakadiException
+ Network.Nakadi.Internal.Http: SubscriptionId :: UUID -> SubscriptionId
+ Network.Nakadi.Internal.Http: SubscriptionNotFound :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: SubscriptionPositionBegin :: SubscriptionPosition
+ Network.Nakadi.Internal.Http: SubscriptionPositionCursors :: SubscriptionPosition
+ Network.Nakadi.Internal.Http: SubscriptionPositionEnd :: SubscriptionPosition
+ Network.Nakadi.Internal.Http: SubscriptionsListResponse :: PaginationLinks -> [Subscription] -> SubscriptionsListResponse
+ Network.Nakadi.Internal.Http: Timestamp :: UTCTime -> Timestamp
+ Network.Nakadi.Internal.Http: TooManyRequests :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: UnexpectedResponse :: (Response ()) -> NakadiException
+ Network.Nakadi.Internal.Http: UnprocessableEntity :: Problem -> NakadiException
+ Network.Nakadi.Internal.Http: [$sel:_batchFlushTimeout:ConsumeParameters] :: ConsumeParameters -> Maybe Int32
+ Network.Nakadi.Internal.Http: [$sel:_batchLimit:ConsumeParameters] :: ConsumeParameters -> Maybe Int32
+ Network.Nakadi.Internal.Http: [$sel:_category:EventType] :: EventType -> Maybe EventTypeCategory
+ Network.Nakadi.Internal.Http: [$sel:_compatibilityMode:EventType] :: EventType -> Maybe CompatibilityMode
+ Network.Nakadi.Internal.Http: [$sel:_consumeParameters:Config] :: Config -> ConsumeParameters
+ Network.Nakadi.Internal.Http: [$sel:_consumerGroup:Subscription] :: Subscription -> Maybe Text
+ Network.Nakadi.Internal.Http: [$sel:_createdAt:EventTypeSchema] :: EventTypeSchema -> Maybe Timestamp
+ Network.Nakadi.Internal.Http: [$sel:_createdAt:Subscription] :: Subscription -> Maybe Timestamp
+ Network.Nakadi.Internal.Http: [$sel:_ctxConfig:SubscriptionEventStreamContext] :: SubscriptionEventStreamContext -> Config
+ Network.Nakadi.Internal.Http: [$sel:_cursor:CursorCommitResult] :: CursorCommitResult -> SubscriptionCursor
+ Network.Nakadi.Internal.Http: [$sel:_cursor:EventStreamBatch] :: EventStreamBatch a -> Cursor
+ Network.Nakadi.Internal.Http: [$sel:_cursor:SubscriptionEventStreamBatch] :: SubscriptionEventStreamBatch a -> SubscriptionCursor
+ Network.Nakadi.Internal.Http: [$sel:_cursorToken:SubscriptionCursor] :: SubscriptionCursor -> Text
+ Network.Nakadi.Internal.Http: [$sel:_dataOp:DataChangeEvent] :: DataChangeEvent a -> DataOp
+ Network.Nakadi.Internal.Http: [$sel:_dataType:DataChangeEvent] :: DataChangeEvent a -> Text
+ Network.Nakadi.Internal.Http: [$sel:_defaultStatistic:EventType] :: EventType -> Maybe EventTypeStatistics
+ Network.Nakadi.Internal.Http: [$sel:_deserializationFailureCallback:Config] :: Config -> Maybe (ByteString -> Text -> IO ())
+ Network.Nakadi.Internal.Http: [$sel:_detail:BatchItemResponse] :: BatchItemResponse -> Maybe Text
+ Network.Nakadi.Internal.Http: [$sel:_distance:CursorDistanceResult] :: CursorDistanceResult -> Int64
+ Network.Nakadi.Internal.Http: [$sel:_eid:BatchItemResponse] :: BatchItemResponse -> Maybe EventId
+ Network.Nakadi.Internal.Http: [$sel:_eid:MetadataEnriched] :: MetadataEnriched -> EventId
+ Network.Nakadi.Internal.Http: [$sel:_eid:Metadata] :: Metadata -> EventId
+ Network.Nakadi.Internal.Http: [$sel:_enrichmentStrategies:EventType] :: EventType -> Maybe [EnrichmentStrategy]
+ Network.Nakadi.Internal.Http: [$sel:_eventType:MetadataEnriched] :: MetadataEnriched -> EventTypeName
+ Network.Nakadi.Internal.Http: [$sel:_eventType:SubscriptionCursorWithoutToken] :: SubscriptionCursorWithoutToken -> EventTypeName
+ Network.Nakadi.Internal.Http: [$sel:_eventType:SubscriptionCursor] :: SubscriptionCursor -> EventTypeName
+ Network.Nakadi.Internal.Http: [$sel:_eventType:SubscriptionEventTypeStats] :: SubscriptionEventTypeStats -> EventTypeName
+ Network.Nakadi.Internal.Http: [$sel:_eventTypes:Subscription] :: Subscription -> [EventTypeName]
+ Network.Nakadi.Internal.Http: [$sel:_events:EventStreamBatch] :: EventStreamBatch a -> Maybe (Vector (EventEnriched a))
+ Network.Nakadi.Internal.Http: [$sel:_events:SubscriptionEventStreamBatch] :: SubscriptionEventStreamBatch a -> Maybe (Vector (EventEnriched a))
+ Network.Nakadi.Internal.Http: [$sel:_finalCursor:CursorDistanceQuery] :: CursorDistanceQuery -> Cursor
+ Network.Nakadi.Internal.Http: [$sel:_flowId:ConsumeParameters] :: ConsumeParameters -> Maybe Text
+ Network.Nakadi.Internal.Http: [$sel:_flowId:MetadataEnriched] :: MetadataEnriched -> Maybe FlowId
+ Network.Nakadi.Internal.Http: [$sel:_href:PaginationLink] :: PaginationLink -> Text
+ Network.Nakadi.Internal.Http: [$sel:_http:Config] :: Config -> HttpBackend
+ Network.Nakadi.Internal.Http: [$sel:_httpErrorCallback:Config] :: Config -> Maybe HttpErrorCallback
+ Network.Nakadi.Internal.Http: [$sel:_httpLbs:HttpBackend] :: HttpBackend -> Request -> IO (Response ByteString)
+ Network.Nakadi.Internal.Http: [$sel:_id:Subscription] :: Subscription -> Maybe SubscriptionId
+ Network.Nakadi.Internal.Http: [$sel:_initialCursor:CursorDistanceQuery] :: CursorDistanceQuery -> Cursor
+ Network.Nakadi.Internal.Http: [$sel:_initialCursors:Subscription] :: Subscription -> Maybe [SubscriptionCursorWithoutToken]
+ Network.Nakadi.Internal.Http: [$sel:_items:CursorCommitResults] :: CursorCommitResults -> [CursorCommitResult]
+ Network.Nakadi.Internal.Http: [$sel:_items:CursorCommit] :: CursorCommit -> [Cursor]
+ Network.Nakadi.Internal.Http: [$sel:_items:EventTypeSchemasResponse] :: EventTypeSchemasResponse -> [EventTypeSchema]
+ Network.Nakadi.Internal.Http: [$sel:_items:SubscriptionCursorCommit] :: SubscriptionCursorCommit -> [SubscriptionCursor]
+ Network.Nakadi.Internal.Http: [$sel:_items:SubscriptionEventTypeStatsResult] :: SubscriptionEventTypeStatsResult -> [SubscriptionEventTypeStats]
+ Network.Nakadi.Internal.Http: [$sel:_items:SubscriptionsListResponse] :: SubscriptionsListResponse -> [Subscription]
+ Network.Nakadi.Internal.Http: [$sel:_links:EventTypeSchemasResponse] :: EventTypeSchemasResponse -> PaginationLinks
+ Network.Nakadi.Internal.Http: [$sel:_links:SubscriptionsListResponse] :: SubscriptionsListResponse -> PaginationLinks
+ Network.Nakadi.Internal.Http: [$sel:_logFunc:Config] :: Config -> Maybe LogFunc
+ Network.Nakadi.Internal.Http: [$sel:_manager:Config] :: Config -> Manager
+ Network.Nakadi.Internal.Http: [$sel:_maxUncommittedEvents:ConsumeParameters] :: ConsumeParameters -> Maybe Int32
+ Network.Nakadi.Internal.Http: [$sel:_messageSize:EventTypeStatistics] :: EventTypeStatistics -> Int64
+ Network.Nakadi.Internal.Http: [$sel:_messagesPerMinute:EventTypeStatistics] :: EventTypeStatistics -> Int64
+ Network.Nakadi.Internal.Http: [$sel:_metadata:DataChangeEvent] :: DataChangeEvent a -> Metadata
+ Network.Nakadi.Internal.Http: [$sel:_metadata:EventEnriched] :: EventEnriched a -> MetadataEnriched
+ Network.Nakadi.Internal.Http: [$sel:_metadata:Event] :: Event a -> Metadata
+ Network.Nakadi.Internal.Http: [$sel:_name:EventType] :: EventType -> EventTypeName
+ Network.Nakadi.Internal.Http: [$sel:_newestAvailableOffset:Partition] :: Partition -> CursorOffset
+ Network.Nakadi.Internal.Http: [$sel:_next:PaginationLinks] :: PaginationLinks -> Maybe PaginationLink
+ Network.Nakadi.Internal.Http: [$sel:_occurredAt:MetadataEnriched] :: MetadataEnriched -> Timestamp
+ Network.Nakadi.Internal.Http: [$sel:_occurredAt:Metadata] :: Metadata -> Timestamp
+ Network.Nakadi.Internal.Http: [$sel:_offset:Cursor] :: Cursor -> CursorOffset
+ Network.Nakadi.Internal.Http: [$sel:_offset:ShiftedCursor] :: ShiftedCursor -> CursorOffset
+ Network.Nakadi.Internal.Http: [$sel:_offset:SubscriptionCursorWithoutToken] :: SubscriptionCursorWithoutToken -> CursorOffset
+ Network.Nakadi.Internal.Http: [$sel:_offset:SubscriptionCursor] :: SubscriptionCursor -> CursorOffset
+ Network.Nakadi.Internal.Http: [$sel:_oldestAvailableOffset:Partition] :: Partition -> CursorOffset
+ Network.Nakadi.Internal.Http: [$sel:_options:EventType] :: EventType -> Maybe EventTypeOptions
+ Network.Nakadi.Internal.Http: [$sel:_owningApplication:EventType] :: EventType -> Maybe ApplicationName
+ Network.Nakadi.Internal.Http: [$sel:_owningApplication:Subscription] :: Subscription -> ApplicationName
+ Network.Nakadi.Internal.Http: [$sel:_parentEids:MetadataEnriched] :: MetadataEnriched -> Maybe [EventId]
+ Network.Nakadi.Internal.Http: [$sel:_parentEids:Metadata] :: Metadata -> Maybe [EventId]
+ Network.Nakadi.Internal.Http: [$sel:_partition:Cursor] :: Cursor -> PartitionName
+ Network.Nakadi.Internal.Http: [$sel:_partition:MetadataEnriched] :: MetadataEnriched -> Maybe PartitionName
+ Network.Nakadi.Internal.Http: [$sel:_partition:Metadata] :: Metadata -> Maybe PartitionName
+ Network.Nakadi.Internal.Http: [$sel:_partition:PartitionStat] :: PartitionStat -> PartitionName
+ Network.Nakadi.Internal.Http: [$sel:_partition:Partition] :: Partition -> PartitionName
+ Network.Nakadi.Internal.Http: [$sel:_partition:ShiftedCursor] :: ShiftedCursor -> PartitionName
+ Network.Nakadi.Internal.Http: [$sel:_partition:SubscriptionCursorWithoutToken] :: SubscriptionCursorWithoutToken -> PartitionName
+ Network.Nakadi.Internal.Http: [$sel:_partition:SubscriptionCursor] :: SubscriptionCursor -> PartitionName
+ Network.Nakadi.Internal.Http: [$sel:_partitionKeyFields:EventType] :: EventType -> Maybe [PartitionKeyField]
+ Network.Nakadi.Internal.Http: [$sel:_partitionStrategy:EventType] :: EventType -> Maybe PartitionStrategy
+ Network.Nakadi.Internal.Http: [$sel:_partitions:SubscriptionEventTypeStats] :: SubscriptionEventTypeStats -> [PartitionStat]
+ Network.Nakadi.Internal.Http: [$sel:_payload:DataChangeEvent] :: DataChangeEvent a -> a
+ Network.Nakadi.Internal.Http: [$sel:_payload:EventEnriched] :: EventEnriched a -> a
+ Network.Nakadi.Internal.Http: [$sel:_payload:Event] :: Event a -> a
+ Network.Nakadi.Internal.Http: [$sel:_prev:PaginationLinks] :: PaginationLinks -> Maybe PaginationLink
+ Network.Nakadi.Internal.Http: [$sel:_publishingStatus:BatchItemResponse] :: BatchItemResponse -> PublishingStatus
+ Network.Nakadi.Internal.Http: [$sel:_readFrom:Subscription] :: Subscription -> Maybe SubscriptionPosition
+ Network.Nakadi.Internal.Http: [$sel:_readParallelism:EventTypeStatistics] :: EventTypeStatistics -> Int64
+ Network.Nakadi.Internal.Http: [$sel:_receivedAt:MetadataEnriched] :: MetadataEnriched -> Timestamp
+ Network.Nakadi.Internal.Http: [$sel:_requestModifier:Config] :: Config -> Request -> IO Request
+ Network.Nakadi.Internal.Http: [$sel:_requestTemplate:Config] :: Config -> Request
+ Network.Nakadi.Internal.Http: [$sel:_responseClose:HttpBackend] :: HttpBackend -> Response BodyReader -> IO ()
+ Network.Nakadi.Internal.Http: [$sel:_responseOpen:HttpBackend] :: HttpBackend -> Request -> Manager -> IO (Response BodyReader)
+ Network.Nakadi.Internal.Http: [$sel:_result:CursorCommitResult] :: CursorCommitResult -> CursorCommitResultType
+ Network.Nakadi.Internal.Http: [$sel:_retentionTime:EventTypeOptions] :: EventTypeOptions -> Int64
+ Network.Nakadi.Internal.Http: [$sel:_retryPolicy:Config] :: Config -> RetryPolicyM IO
+ Network.Nakadi.Internal.Http: [$sel:_schema:EventTypeSchema] :: EventTypeSchema -> Text
+ Network.Nakadi.Internal.Http: [$sel:_schema:EventType] :: EventType -> EventTypeSchema
+ Network.Nakadi.Internal.Http: [$sel:_schemaType:EventTypeSchema] :: EventTypeSchema -> SchemaType
+ Network.Nakadi.Internal.Http: [$sel:_shift:ShiftedCursor] :: ShiftedCursor -> Int64
+ Network.Nakadi.Internal.Http: [$sel:_state:PartitionStat] :: PartitionStat -> PartitionState
+ Network.Nakadi.Internal.Http: [$sel:_step:BatchItemResponse] :: BatchItemResponse -> Maybe Step
+ Network.Nakadi.Internal.Http: [$sel:_streamConnectCallback:Config] :: Config -> Maybe StreamConnectCallback
+ Network.Nakadi.Internal.Http: [$sel:_streamId:PartitionStat] :: PartitionStat -> StreamId
+ Network.Nakadi.Internal.Http: [$sel:_streamId:SubscriptionEventStreamContext] :: SubscriptionEventStreamContext -> StreamId
+ Network.Nakadi.Internal.Http: [$sel:_streamId:SubscriptionEventStream] :: SubscriptionEventStream -> StreamId
+ Network.Nakadi.Internal.Http: [$sel:_streamKeepAliveLimit:ConsumeParameters] :: ConsumeParameters -> Maybe Int32
+ Network.Nakadi.Internal.Http: [$sel:_streamLimit:ConsumeParameters] :: ConsumeParameters -> Maybe Int32
+ Network.Nakadi.Internal.Http: [$sel:_streamTimeout:ConsumeParameters] :: ConsumeParameters -> Maybe Int32
+ Network.Nakadi.Internal.Http: [$sel:_subscriptionId:SubscriptionEventStreamContext] :: SubscriptionEventStreamContext -> SubscriptionId
+ Network.Nakadi.Internal.Http: [$sel:_subscriptionId:SubscriptionEventStream] :: SubscriptionEventStream -> SubscriptionId
+ Network.Nakadi.Internal.Http: [$sel:_unconsumedEvents:PartitionStat] :: PartitionStat -> Int64
+ Network.Nakadi.Internal.Http: [$sel:_unconsumedEvents:Partition] :: Partition -> Maybe Int64
+ Network.Nakadi.Internal.Http: [$sel:_version:EventTypeSchema] :: EventTypeSchema -> Maybe SchemaVersion
+ Network.Nakadi.Internal.Http: [$sel:_version:MetadataEnriched] :: MetadataEnriched -> SchemaVersion
+ Network.Nakadi.Internal.Http: [$sel:_writeParallelism:EventTypeStatistics] :: EventTypeStatistics -> Int64
+ Network.Nakadi.Internal.Http: [$sel:problemCustom:Problem] :: Problem -> Maybe (HashMap Text Value)
+ Network.Nakadi.Internal.Http: [$sel:problemDetail:Problem] :: Problem -> Maybe Text
+ Network.Nakadi.Internal.Http: [$sel:problemInstance:Problem] :: Problem -> Maybe Text
+ Network.Nakadi.Internal.Http: [$sel:problemStatus:Problem] :: Problem -> Int32
+ Network.Nakadi.Internal.Http: [$sel:problemTitle:Problem] :: Problem -> Text
+ Network.Nakadi.Internal.Http: [$sel:problemType:Problem] :: Problem -> Text
+ Network.Nakadi.Internal.Http: [$sel:unApplicationName:ApplicationName] :: ApplicationName -> Text
+ Network.Nakadi.Internal.Http: [$sel:unBatchFlushTimeout:BatchFlushTimeout] :: BatchFlushTimeout -> Int32
+ Network.Nakadi.Internal.Http: [$sel:unCursorOffset:CursorOffset] :: CursorOffset -> Text
+ Network.Nakadi.Internal.Http: [$sel:unEventId:EventId] :: EventId -> UUID
+ Network.Nakadi.Internal.Http: [$sel:unEventTypeName:EventTypeName] :: EventTypeName -> Text
+ Network.Nakadi.Internal.Http: [$sel:unFlowId:FlowId] :: FlowId -> Text
+ Network.Nakadi.Internal.Http: [$sel:unLimit:Limit] :: Limit -> Int64
+ Network.Nakadi.Internal.Http: [$sel:unOffset:Offset] :: Offset -> Int64
+ Network.Nakadi.Internal.Http: [$sel:unPartitionKeyField:PartitionKeyField] :: PartitionKeyField -> Text
+ Network.Nakadi.Internal.Http: [$sel:unPartitionName:PartitionName] :: PartitionName -> Text
+ Network.Nakadi.Internal.Http: [$sel:unSchemaVersion:SchemaVersion] :: SchemaVersion -> Text
+ Network.Nakadi.Internal.Http: [$sel:unStreamId:StreamId] :: StreamId -> Text
+ Network.Nakadi.Internal.Http: [$sel:unStreamKeepAliveLimit:StreamKeepAliveLimit] :: StreamKeepAliveLimit -> Int32
+ Network.Nakadi.Internal.Http: [$sel:unSubscriptionId:SubscriptionId] :: SubscriptionId -> UUID
+ Network.Nakadi.Internal.Http: [$sel:unTimestamp:Timestamp] :: Timestamp -> UTCTime
+ Network.Nakadi.Internal.Http: class HasNakadiConfig s a
+ Network.Nakadi.Internal.Http: data BatchItemResponse
+ Network.Nakadi.Internal.Http: data CompatibilityMode
+ Network.Nakadi.Internal.Http: data Config
+ Network.Nakadi.Internal.Http: data ConsumeParameters
+ Network.Nakadi.Internal.Http: data Cursor
+ Network.Nakadi.Internal.Http: data CursorCommitResult
+ Network.Nakadi.Internal.Http: data CursorCommitResultType
+ Network.Nakadi.Internal.Http: data CursorDistanceQuery
+ Network.Nakadi.Internal.Http: data DataChangeEvent a
+ Network.Nakadi.Internal.Http: data DataOp
+ Network.Nakadi.Internal.Http: data EnrichmentStrategy
+ Network.Nakadi.Internal.Http: data Event a
+ Network.Nakadi.Internal.Http: data EventEnriched a
+ Network.Nakadi.Internal.Http: data EventStreamBatch a
+ Network.Nakadi.Internal.Http: data EventType
+ Network.Nakadi.Internal.Http: data EventTypeCategory
+ Network.Nakadi.Internal.Http: data EventTypeOptions
+ Network.Nakadi.Internal.Http: data EventTypeSchema
+ Network.Nakadi.Internal.Http: data EventTypeSchemasResponse
+ Network.Nakadi.Internal.Http: data EventTypeStatistics
+ Network.Nakadi.Internal.Http: data HttpBackend
+ Network.Nakadi.Internal.Http: data Metadata
+ Network.Nakadi.Internal.Http: data MetadataEnriched
+ Network.Nakadi.Internal.Http: data NakadiException
+ Network.Nakadi.Internal.Http: data PaginationLinks
+ Network.Nakadi.Internal.Http: data Partition
+ Network.Nakadi.Internal.Http: data PartitionStat
+ Network.Nakadi.Internal.Http: data PartitionState
+ Network.Nakadi.Internal.Http: data PartitionStrategy
+ Network.Nakadi.Internal.Http: data Problem
+ Network.Nakadi.Internal.Http: data PublishingStatus
+ Network.Nakadi.Internal.Http: data SchemaType
+ Network.Nakadi.Internal.Http: data ShiftedCursor
+ Network.Nakadi.Internal.Http: data Step
+ Network.Nakadi.Internal.Http: data Subscription
+ Network.Nakadi.Internal.Http: data SubscriptionCursor
+ Network.Nakadi.Internal.Http: data SubscriptionCursorWithoutToken
+ Network.Nakadi.Internal.Http: data SubscriptionEventStream
+ Network.Nakadi.Internal.Http: data SubscriptionEventStreamBatch a
+ Network.Nakadi.Internal.Http: data SubscriptionEventStreamContext
+ Network.Nakadi.Internal.Http: data SubscriptionEventTypeStats
+ Network.Nakadi.Internal.Http: data SubscriptionPosition
+ Network.Nakadi.Internal.Http: data SubscriptionsListResponse
+ Network.Nakadi.Internal.Http: errorAccessForbidden :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorBadRequest :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorBatchNotSubmitted :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorBatchPartiallySubmitted :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorClientNotAuthenticated :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorCursorAlreadyCommitted :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorCursorResetInProgress :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorEventTypeNotFound :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorSubscriptionExistsAlready :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorSubscriptionNotFound :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorTooManyRequests :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: errorUnprocessableEntity :: MonadThrow m => ByteString -> m NakadiException
+ Network.Nakadi.Internal.Http: httpJsonBody :: (MonadMask m, MonadIO m, FromJSON a) => Config -> Status -> [(Status, ByteString -> m NakadiException)] -> (Request -> Request) -> m a
+ Network.Nakadi.Internal.Http: httpJsonBodyStream :: (MonadMask m, MonadIO m, FromJSON a, MonadBaseControl IO m, MonadResource m) => Config -> Status -> (Response () -> Either Text b) -> [(Status, ByteString -> m NakadiException)] -> (Request -> Request) -> m (b, ConduitM () a (ReaderT r m) ())
+ Network.Nakadi.Internal.Http: httpJsonNoBody :: (MonadMask m, MonadIO m) => Config -> Status -> [(Status, ByteString -> m NakadiException)] -> (Request -> Request) -> m ()
+ Network.Nakadi.Internal.Http: makeFieldRenamer :: [(String, String)] -> String -> String
+ Network.Nakadi.Internal.Http: newtype ApplicationName
+ Network.Nakadi.Internal.Http: newtype BatchFlushTimeout
+ Network.Nakadi.Internal.Http: newtype CursorCommit
+ Network.Nakadi.Internal.Http: newtype CursorCommitResults
+ Network.Nakadi.Internal.Http: newtype CursorDistanceResult
+ Network.Nakadi.Internal.Http: newtype CursorOffset
+ Network.Nakadi.Internal.Http: newtype CursorToken
+ Network.Nakadi.Internal.Http: newtype EventId
+ Network.Nakadi.Internal.Http: newtype EventTypeName
+ Network.Nakadi.Internal.Http: newtype FlowId
+ Network.Nakadi.Internal.Http: newtype Limit
+ Network.Nakadi.Internal.Http: newtype Offset
+ Network.Nakadi.Internal.Http: newtype PaginationLink
+ Network.Nakadi.Internal.Http: newtype PartitionKeyField
+ Network.Nakadi.Internal.Http: newtype PartitionName
+ Network.Nakadi.Internal.Http: newtype SchemaVersion
+ Network.Nakadi.Internal.Http: newtype StreamId
+ Network.Nakadi.Internal.Http: newtype StreamKeepAliveLimit
+ Network.Nakadi.Internal.Http: newtype SubscriptionCursorCommit
+ Network.Nakadi.Internal.Http: newtype SubscriptionEventTypeStatsResult
+ Network.Nakadi.Internal.Http: newtype SubscriptionId
+ Network.Nakadi.Internal.Http: newtype Timestamp
+ Network.Nakadi.Internal.Http: parseInteger :: (Integral i, Bounded i) => String -> (i -> a) -> Value -> Parser a
+ Network.Nakadi.Internal.Http: parseUUID :: String -> (UUID -> a) -> Value -> Parser a
+ Network.Nakadi.Internal.Http: setRequestQueryParameters :: [(ByteString, ByteString)] -> Request -> Request
+ Network.Nakadi.Internal.Http: type HttpErrorCallback = Request -> HttpException -> RetryStatus -> Bool -> IO ()
+ Network.Nakadi.Internal.Http: type LogFunc = Loc -> LogSource -> LogLevel -> LogStr -> IO ()
+ Network.Nakadi.Internal.Http: type MonadNakadi m = (MonadIO m, MonadCatch m, MonadThrow m, MonadMask m)
+ Network.Nakadi.Internal.Http: type MonadNakadiEnv r m = (MonadNakadi m, MonadReader r m, HasNakadiConfig r Config)
+ Network.Nakadi.Internal.Http: type StreamConnectCallback = Maybe LogFunc -> Response () -> IO ()
+ Network.Nakadi.Internal.Retry: retryAction :: (MonadIO m, MonadMask m) => Config -> Request -> (Request -> m a) -> m a
+ Network.Nakadi.Types.Config: HttpBackend :: (Request -> IO (Response ByteString)) -> (Request -> Manager -> IO (Response BodyReader)) -> (Response BodyReader -> IO ()) -> HttpBackend
+ Network.Nakadi.Types.Config: [$sel:_httpLbs:HttpBackend] :: HttpBackend -> Request -> IO (Response ByteString)
+ Network.Nakadi.Types.Config: [$sel:_responseClose:HttpBackend] :: HttpBackend -> Response BodyReader -> IO ()
+ Network.Nakadi.Types.Config: [$sel:_responseOpen:HttpBackend] :: HttpBackend -> Request -> Manager -> IO (Response BodyReader)
+ Network.Nakadi.Types.Config: data HttpBackend
+ Network.Nakadi.Types.Problem: [$sel:problemCustom:Problem] :: Problem -> Maybe (HashMap Text Value)
+ Network.Nakadi.Types.Problem: [$sel:problemDetail:Problem] :: Problem -> Maybe Text
+ Network.Nakadi.Types.Problem: [$sel:problemInstance:Problem] :: Problem -> Maybe Text
+ Network.Nakadi.Types.Problem: [$sel:problemStatus:Problem] :: Problem -> Int32
+ Network.Nakadi.Types.Problem: [$sel:problemTitle:Problem] :: Problem -> Text
+ Network.Nakadi.Types.Problem: [$sel:problemType:Problem] :: Problem -> Text
+ Network.Nakadi.Types.Service: CursorCommitResults :: [CursorCommitResult] -> CursorCommitResults
+ Network.Nakadi.Types.Service: [$sel:_category:EventType] :: EventType -> Maybe EventTypeCategory
+ Network.Nakadi.Types.Service: [$sel:_compatibilityMode:EventType] :: EventType -> Maybe CompatibilityMode
+ Network.Nakadi.Types.Service: [$sel:_consumerGroup:Subscription] :: Subscription -> Maybe Text
+ Network.Nakadi.Types.Service: [$sel:_createdAt:EventTypeSchema] :: EventTypeSchema -> Maybe Timestamp
+ Network.Nakadi.Types.Service: [$sel:_createdAt:Subscription] :: Subscription -> Maybe Timestamp
+ Network.Nakadi.Types.Service: [$sel:_cursor:CursorCommitResult] :: CursorCommitResult -> SubscriptionCursor
+ Network.Nakadi.Types.Service: [$sel:_cursor:EventStreamBatch] :: EventStreamBatch a -> Cursor
+ Network.Nakadi.Types.Service: [$sel:_cursor:SubscriptionEventStreamBatch] :: SubscriptionEventStreamBatch a -> SubscriptionCursor
+ Network.Nakadi.Types.Service: [$sel:_cursorToken:SubscriptionCursor] :: SubscriptionCursor -> Text
+ Network.Nakadi.Types.Service: [$sel:_dataOp:DataChangeEvent] :: DataChangeEvent a -> DataOp
+ Network.Nakadi.Types.Service: [$sel:_dataType:DataChangeEvent] :: DataChangeEvent a -> Text
+ Network.Nakadi.Types.Service: [$sel:_defaultStatistic:EventType] :: EventType -> Maybe EventTypeStatistics
+ Network.Nakadi.Types.Service: [$sel:_detail:BatchItemResponse] :: BatchItemResponse -> Maybe Text
+ Network.Nakadi.Types.Service: [$sel:_distance:CursorDistanceResult] :: CursorDistanceResult -> Int64
+ Network.Nakadi.Types.Service: [$sel:_eid:BatchItemResponse] :: BatchItemResponse -> Maybe EventId
+ Network.Nakadi.Types.Service: [$sel:_eid:MetadataEnriched] :: MetadataEnriched -> EventId
+ Network.Nakadi.Types.Service: [$sel:_eid:Metadata] :: Metadata -> EventId
+ Network.Nakadi.Types.Service: [$sel:_enrichmentStrategies:EventType] :: EventType -> Maybe [EnrichmentStrategy]
+ Network.Nakadi.Types.Service: [$sel:_eventType:MetadataEnriched] :: MetadataEnriched -> EventTypeName
+ Network.Nakadi.Types.Service: [$sel:_eventType:SubscriptionCursorWithoutToken] :: SubscriptionCursorWithoutToken -> EventTypeName
+ Network.Nakadi.Types.Service: [$sel:_eventType:SubscriptionCursor] :: SubscriptionCursor -> EventTypeName
+ Network.Nakadi.Types.Service: [$sel:_eventType:SubscriptionEventTypeStats] :: SubscriptionEventTypeStats -> EventTypeName
+ Network.Nakadi.Types.Service: [$sel:_eventTypes:Subscription] :: Subscription -> [EventTypeName]
+ Network.Nakadi.Types.Service: [$sel:_events:EventStreamBatch] :: EventStreamBatch a -> Maybe (Vector (EventEnriched a))
+ Network.Nakadi.Types.Service: [$sel:_events:SubscriptionEventStreamBatch] :: SubscriptionEventStreamBatch a -> Maybe (Vector (EventEnriched a))
+ Network.Nakadi.Types.Service: [$sel:_finalCursor:CursorDistanceQuery] :: CursorDistanceQuery -> Cursor
+ Network.Nakadi.Types.Service: [$sel:_flowId:MetadataEnriched] :: MetadataEnriched -> Maybe FlowId
+ Network.Nakadi.Types.Service: [$sel:_href:PaginationLink] :: PaginationLink -> Text
+ Network.Nakadi.Types.Service: [$sel:_id:Subscription] :: Subscription -> Maybe SubscriptionId
+ Network.Nakadi.Types.Service: [$sel:_initialCursor:CursorDistanceQuery] :: CursorDistanceQuery -> Cursor
+ Network.Nakadi.Types.Service: [$sel:_initialCursors:Subscription] :: Subscription -> Maybe [SubscriptionCursorWithoutToken]
+ Network.Nakadi.Types.Service: [$sel:_items:CursorCommitResults] :: CursorCommitResults -> [CursorCommitResult]
+ Network.Nakadi.Types.Service: [$sel:_items:CursorCommit] :: CursorCommit -> [Cursor]
+ Network.Nakadi.Types.Service: [$sel:_items:EventTypeSchemasResponse] :: EventTypeSchemasResponse -> [EventTypeSchema]
+ Network.Nakadi.Types.Service: [$sel:_items:SubscriptionCursorCommit] :: SubscriptionCursorCommit -> [SubscriptionCursor]
+ Network.Nakadi.Types.Service: [$sel:_items:SubscriptionEventTypeStatsResult] :: SubscriptionEventTypeStatsResult -> [SubscriptionEventTypeStats]
+ Network.Nakadi.Types.Service: [$sel:_items:SubscriptionsListResponse] :: SubscriptionsListResponse -> [Subscription]
+ Network.Nakadi.Types.Service: [$sel:_links:EventTypeSchemasResponse] :: EventTypeSchemasResponse -> PaginationLinks
+ Network.Nakadi.Types.Service: [$sel:_links:SubscriptionsListResponse] :: SubscriptionsListResponse -> PaginationLinks
+ Network.Nakadi.Types.Service: [$sel:_messageSize:EventTypeStatistics] :: EventTypeStatistics -> Int64
+ Network.Nakadi.Types.Service: [$sel:_messagesPerMinute:EventTypeStatistics] :: EventTypeStatistics -> Int64
+ Network.Nakadi.Types.Service: [$sel:_metadata:DataChangeEvent] :: DataChangeEvent a -> Metadata
+ Network.Nakadi.Types.Service: [$sel:_metadata:EventEnriched] :: EventEnriched a -> MetadataEnriched
+ Network.Nakadi.Types.Service: [$sel:_metadata:Event] :: Event a -> Metadata
+ Network.Nakadi.Types.Service: [$sel:_name:EventType] :: EventType -> EventTypeName
+ Network.Nakadi.Types.Service: [$sel:_newestAvailableOffset:Partition] :: Partition -> CursorOffset
+ Network.Nakadi.Types.Service: [$sel:_next:PaginationLinks] :: PaginationLinks -> Maybe PaginationLink
+ Network.Nakadi.Types.Service: [$sel:_occurredAt:MetadataEnriched] :: MetadataEnriched -> Timestamp
+ Network.Nakadi.Types.Service: [$sel:_occurredAt:Metadata] :: Metadata -> Timestamp
+ Network.Nakadi.Types.Service: [$sel:_offset:Cursor] :: Cursor -> CursorOffset
+ Network.Nakadi.Types.Service: [$sel:_offset:ShiftedCursor] :: ShiftedCursor -> CursorOffset
+ Network.Nakadi.Types.Service: [$sel:_offset:SubscriptionCursorWithoutToken] :: SubscriptionCursorWithoutToken -> CursorOffset
+ Network.Nakadi.Types.Service: [$sel:_offset:SubscriptionCursor] :: SubscriptionCursor -> CursorOffset
+ Network.Nakadi.Types.Service: [$sel:_oldestAvailableOffset:Partition] :: Partition -> CursorOffset
+ Network.Nakadi.Types.Service: [$sel:_options:EventType] :: EventType -> Maybe EventTypeOptions
+ Network.Nakadi.Types.Service: [$sel:_owningApplication:EventType] :: EventType -> Maybe ApplicationName
+ Network.Nakadi.Types.Service: [$sel:_owningApplication:Subscription] :: Subscription -> ApplicationName
+ Network.Nakadi.Types.Service: [$sel:_parentEids:MetadataEnriched] :: MetadataEnriched -> Maybe [EventId]
+ Network.Nakadi.Types.Service: [$sel:_parentEids:Metadata] :: Metadata -> Maybe [EventId]
+ Network.Nakadi.Types.Service: [$sel:_partition:Cursor] :: Cursor -> PartitionName
+ Network.Nakadi.Types.Service: [$sel:_partition:MetadataEnriched] :: MetadataEnriched -> Maybe PartitionName
+ Network.Nakadi.Types.Service: [$sel:_partition:Metadata] :: Metadata -> Maybe PartitionName
+ Network.Nakadi.Types.Service: [$sel:_partition:PartitionStat] :: PartitionStat -> PartitionName
+ Network.Nakadi.Types.Service: [$sel:_partition:Partition] :: Partition -> PartitionName
+ Network.Nakadi.Types.Service: [$sel:_partition:ShiftedCursor] :: ShiftedCursor -> PartitionName
+ Network.Nakadi.Types.Service: [$sel:_partition:SubscriptionCursorWithoutToken] :: SubscriptionCursorWithoutToken -> PartitionName
+ Network.Nakadi.Types.Service: [$sel:_partition:SubscriptionCursor] :: SubscriptionCursor -> PartitionName
+ Network.Nakadi.Types.Service: [$sel:_partitionKeyFields:EventType] :: EventType -> Maybe [PartitionKeyField]
+ Network.Nakadi.Types.Service: [$sel:_partitionStrategy:EventType] :: EventType -> Maybe PartitionStrategy
+ Network.Nakadi.Types.Service: [$sel:_partitions:SubscriptionEventTypeStats] :: SubscriptionEventTypeStats -> [PartitionStat]
+ Network.Nakadi.Types.Service: [$sel:_payload:DataChangeEvent] :: DataChangeEvent a -> a
+ Network.Nakadi.Types.Service: [$sel:_payload:EventEnriched] :: EventEnriched a -> a
+ Network.Nakadi.Types.Service: [$sel:_payload:Event] :: Event a -> a
+ Network.Nakadi.Types.Service: [$sel:_prev:PaginationLinks] :: PaginationLinks -> Maybe PaginationLink
+ Network.Nakadi.Types.Service: [$sel:_publishingStatus:BatchItemResponse] :: BatchItemResponse -> PublishingStatus
+ Network.Nakadi.Types.Service: [$sel:_readFrom:Subscription] :: Subscription -> Maybe SubscriptionPosition
+ Network.Nakadi.Types.Service: [$sel:_readParallelism:EventTypeStatistics] :: EventTypeStatistics -> Int64
+ Network.Nakadi.Types.Service: [$sel:_receivedAt:MetadataEnriched] :: MetadataEnriched -> Timestamp
+ Network.Nakadi.Types.Service: [$sel:_result:CursorCommitResult] :: CursorCommitResult -> CursorCommitResultType
+ Network.Nakadi.Types.Service: [$sel:_retentionTime:EventTypeOptions] :: EventTypeOptions -> Int64
+ Network.Nakadi.Types.Service: [$sel:_schema:EventTypeSchema] :: EventTypeSchema -> Text
+ Network.Nakadi.Types.Service: [$sel:_schema:EventType] :: EventType -> EventTypeSchema
+ Network.Nakadi.Types.Service: [$sel:_schemaType:EventTypeSchema] :: EventTypeSchema -> SchemaType
+ Network.Nakadi.Types.Service: [$sel:_shift:ShiftedCursor] :: ShiftedCursor -> Int64
+ Network.Nakadi.Types.Service: [$sel:_state:PartitionStat] :: PartitionStat -> PartitionState
+ Network.Nakadi.Types.Service: [$sel:_step:BatchItemResponse] :: BatchItemResponse -> Maybe Step
+ Network.Nakadi.Types.Service: [$sel:_streamId:PartitionStat] :: PartitionStat -> StreamId
+ Network.Nakadi.Types.Service: [$sel:_streamId:SubscriptionEventStream] :: SubscriptionEventStream -> StreamId
+ Network.Nakadi.Types.Service: [$sel:_subscriptionId:SubscriptionEventStream] :: SubscriptionEventStream -> SubscriptionId
+ Network.Nakadi.Types.Service: [$sel:_unconsumedEvents:PartitionStat] :: PartitionStat -> Int64
+ Network.Nakadi.Types.Service: [$sel:_unconsumedEvents:Partition] :: Partition -> Maybe Int64
+ Network.Nakadi.Types.Service: [$sel:_version:EventTypeSchema] :: EventTypeSchema -> Maybe SchemaVersion
+ Network.Nakadi.Types.Service: [$sel:_version:MetadataEnriched] :: MetadataEnriched -> SchemaVersion
+ Network.Nakadi.Types.Service: [$sel:_writeParallelism:EventTypeStatistics] :: EventTypeStatistics -> Int64
+ Network.Nakadi.Types.Service: [$sel:unApplicationName:ApplicationName] :: ApplicationName -> Text
+ Network.Nakadi.Types.Service: [$sel:unBatchFlushTimeout:BatchFlushTimeout] :: BatchFlushTimeout -> Int32
+ Network.Nakadi.Types.Service: [$sel:unCursorOffset:CursorOffset] :: CursorOffset -> Text
+ Network.Nakadi.Types.Service: [$sel:unEventId:EventId] :: EventId -> UUID
+ Network.Nakadi.Types.Service: [$sel:unEventTypeName:EventTypeName] :: EventTypeName -> Text
+ Network.Nakadi.Types.Service: [$sel:unFlowId:FlowId] :: FlowId -> Text
+ Network.Nakadi.Types.Service: [$sel:unLimit:Limit] :: Limit -> Int64
+ Network.Nakadi.Types.Service: [$sel:unOffset:Offset] :: Offset -> Int64
+ Network.Nakadi.Types.Service: [$sel:unPartitionKeyField:PartitionKeyField] :: PartitionKeyField -> Text
+ Network.Nakadi.Types.Service: [$sel:unPartitionName:PartitionName] :: PartitionName -> Text
+ Network.Nakadi.Types.Service: [$sel:unSchemaVersion:SchemaVersion] :: SchemaVersion -> Text
+ Network.Nakadi.Types.Service: [$sel:unStreamId:StreamId] :: StreamId -> Text
+ Network.Nakadi.Types.Service: [$sel:unStreamKeepAliveLimit:StreamKeepAliveLimit] :: StreamKeepAliveLimit -> Int32
+ Network.Nakadi.Types.Service: [$sel:unSubscriptionId:SubscriptionId] :: SubscriptionId -> UUID
+ Network.Nakadi.Types.Service: [$sel:unTimestamp:Timestamp] :: Timestamp -> UTCTime
+ Network.Nakadi.Types.Service: newtype CursorCommitResults
+ Network.Nakadi.Types.Subscription: SubscriptionEventStreamContext :: StreamId -> SubscriptionId -> Config -> SubscriptionEventStreamContext
+ Network.Nakadi.Types.Subscription: [$sel:_ctxConfig:SubscriptionEventStreamContext] :: SubscriptionEventStreamContext -> Config
+ Network.Nakadi.Types.Subscription: [$sel:_streamId:SubscriptionEventStreamContext] :: SubscriptionEventStreamContext -> StreamId
+ Network.Nakadi.Types.Subscription: [$sel:_subscriptionId:SubscriptionEventStreamContext] :: SubscriptionEventStreamContext -> SubscriptionId
- Network.Nakadi.Subscriptions.Events: runSubscriptionR :: (Monad m, MonadBaseControl IO m, MonadResource m, MonadReader r m, HasNakadiConfig r Config) => SubscriptionEventStream -> ConduitM () Void (ReaderT SubscriptionEventStreamContext m) r -> m r
+ Network.Nakadi.Subscriptions.Events: runSubscriptionR :: (Monad m, MonadBaseControl IO m, MonadResource m, MonadReader r m, HasNakadiConfig r Config) => SubscriptionEventStream -> ConduitM () Void (ReaderT SubscriptionEventStreamContext m) s -> m s
- Network.Nakadi.Types.Exceptions: CursorAlreadyCommitted :: [CursorCommitResult] -> NakadiException
+ Network.Nakadi.Types.Exceptions: CursorAlreadyCommitted :: CursorCommitResults -> NakadiException
- Network.Nakadi.Types.Service: EventStreamBatch :: Cursor -> Maybe (Vector (Event a)) -> EventStreamBatch a
+ Network.Nakadi.Types.Service: EventStreamBatch :: Cursor -> Maybe (Vector (EventEnriched a)) -> EventStreamBatch a
- Network.Nakadi.Types.Service: Metadata :: Text -> Timestamp -> Maybe [Text] -> Maybe Text -> Metadata
+ Network.Nakadi.Types.Service: Metadata :: EventId -> Timestamp -> Maybe [EventId] -> Maybe PartitionName -> Metadata
- Network.Nakadi.Types.Service: MetadataEnriched :: Text -> EventTypeName -> Timestamp -> Timestamp -> SchemaVersion -> Maybe [Text] -> MetadataEnriched
+ Network.Nakadi.Types.Service: MetadataEnriched :: EventId -> EventTypeName -> Timestamp -> Timestamp -> SchemaVersion -> Maybe [EventId] -> Maybe FlowId -> Maybe PartitionName -> MetadataEnriched
- Network.Nakadi.Types.Service: SubscriptionEventStreamBatch :: SubscriptionCursor -> Maybe (Vector (Event a)) -> SubscriptionEventStreamBatch a
+ Network.Nakadi.Types.Service: SubscriptionEventStreamBatch :: SubscriptionCursor -> Maybe (Vector (EventEnriched a)) -> SubscriptionEventStreamBatch a

Files

nakadi-client.cabal view
@@ -1,9 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.17.0.+-- This file has been generated from package.yaml by hpack version 0.20.0. -- -- see: https://github.com/sol/hpack+--+-- hash: 8c95e6f774d7ddcacd71c47566a57d2e35c231b13bd9c2c23808078cfad08542  name:           nakadi-client-version:        0.3.0.0+version:        0.4.0.0 synopsis:       Client library for the Nakadi Event Broker description:    This package implements a client library for interacting with the Nakadi event broker system developed by Zalando. category:       Network@@ -24,42 +26,48 @@   type: git   location: https://github.com/mtesseract/nakadi-haskell +flag devel+  manual: True+  default: False+ library   hs-source-dirs:       src   default-extensions: NoImplicitPrelude OverloadedStrings DuplicateRecordFields-  ghc-options: -Wall -fno-warn-type-defaults   build-depends:-      base >=4.7 && <5+      aeson+    , aeson-casing+    , base >=4.7 && <5+    , bytestring     , conduit-    , conduit-extra     , conduit-combinators-    , iso8601-time-    , bytestring+    , conduit-extra     , containers-    , vector     , hashable-    , aeson-    , monad-logger-    , text-    , lens-    , http-types     , http-client     , http-client-tls     , http-conduit-    , resourcet-    , uuid+    , http-types+    , iso8601-time+    , lens+    , monad-logger     , mtl-    , transformers-    , scientific+    , resourcet+    , retry     , safe-exceptions-    , unordered-containers-    , time+    , scientific     , split-    , aeson-casing-    , tasty     , template-haskell-    , retry+    , text+    , time+    , transformers+    , unordered-containers+    , uuid+    , vector+  if flag(devel)+    ghc-options: -Wall -fno-warn-type-defaults -Werror+  else+    ghc-options: -Wall -fno-warn-type-defaults   exposed-modules:       Network.Nakadi       Network.Nakadi.Config@@ -85,14 +93,14 @@       Network.Nakadi.Types.Subscription       Network.Nakadi.Registry       Network.Nakadi.Lenses+      Network.Nakadi.Internal.Http+      Network.Nakadi.Internal.Retry   other-modules:       Network.Nakadi.Internal.Config       Network.Nakadi.Internal.Conversions-      Network.Nakadi.Internal.Http       Network.Nakadi.Internal.Json       Network.Nakadi.Internal.Lenses       Network.Nakadi.Internal.Prelude-      Network.Nakadi.Internal.Retry       Network.Nakadi.Internal.TH       Network.Nakadi.Internal.Types       Network.Nakadi.Internal.Types.Config@@ -112,57 +120,64 @@   hs-source-dirs:       tests   default-extensions: NoImplicitPrelude OverloadedStrings DuplicateRecordFields-  ghc-options: -Wall -fno-warn-type-defaults -Wall -fno-warn-type-defaults+  ghc-options: -Wall -fno-warn-type-defaults   build-depends:-      base >=4.7 && <5+      aeson+    , aeson-casing+    , async+    , base+    , bytestring+    , classy-prelude     , conduit-    , conduit-extra     , conduit-combinators-    , iso8601-time-    , bytestring+    , conduit-extra     , containers-    , vector     , hashable-    , aeson-    , monad-logger-    , text-    , lens-    , http-types     , http-client     , http-client-tls     , http-conduit-    , resourcet-    , uuid+    , http-types+    , iso8601-time+    , lens+    , lens-aeson+    , monad-logger     , mtl-    , transformers-    , scientific+    , nakadi-client+    , random+    , resourcet+    , retry     , safe-exceptions-    , unordered-containers-    , time+    , say+    , scientific     , split-    , aeson-casing-    , tasty-    , template-haskell-    , retry-    , base-    , classy-prelude-    , nakadi-client+    , stm     , tasty     , tasty-hunit-    , http-client-    , http-conduit-    , aeson-    , lens-aeson+    , template-haskell     , text-    , say-    , random-    , async-    , retry+    , time+    , transformers+    , unordered-containers+    , uuid+    , vector+    , wai+    , warp+  if flag(devel)+    ghc-options: -Wall -fno-warn-type-defaults -Werror+  else+    ghc-options: -Wall -fno-warn-type-defaults   other-modules:+      Network.Nakadi.Config.Test+      Network.Nakadi.Connection.Test       Network.Nakadi.EventTypes.CursorsLag.Test       Network.Nakadi.EventTypes.ShiftedCursors.Test       Network.Nakadi.EventTypes.Test+      Network.Nakadi.Internal.Http.Test+      Network.Nakadi.Internal.Retry.Test+      Network.Nakadi.Internal.Test+      Network.Nakadi.Internal.Types.Test       Network.Nakadi.Registry.Test       Network.Nakadi.Subscriptions.Test       Network.Nakadi.Tests.Common+      Paths_nakadi_client   default-language: Haskell2010
src/Network/Nakadi/Config.hs view
@@ -17,8 +17,11 @@  import           Control.Lens import           Control.Retry-import           Network.HTTP.Client-import           Network.HTTP.Client.TLS+import           Network.HTTP.Client             (Manager, ManagerSettings,+                                                  responseClose, responseOpen)+import           Network.HTTP.Client.TLS         (newTlsManagerWith,+                                                  tlsManagerSettings)+import           Network.HTTP.Simple             (httpLbs) import qualified Network.Nakadi.Internal.Lenses  as L import           Network.Nakadi.Internal.Types @@ -42,8 +45,18 @@                 , _deserializationFailureCallback = Nothing                 , _streamConnectCallback          = Nothing                 , _logFunc                        = Nothing-                , _retryPolicy                    = defaultRetryPolicy }+                , _retryPolicy                    = defaultRetryPolicy+                , _http                           = defaultHttpBackend+                , _httpErrorCallback              = Nothing+                } +-- | Default 'HttpBackend' doing IO using http-client.+defaultHttpBackend :: HttpBackend+defaultHttpBackend =+  HttpBackend { _httpLbs                        = httpLbs+              , _responseOpen                   = responseOpen+              , _responseClose                  = responseClose }+ -- | Produce a new configuration, with optional HTTP manager settings -- and mandatory HTTP request template. newConfig ::@@ -75,6 +88,14 @@ setStreamConnectCallback :: StreamConnectCallback  -> Config -> Config setStreamConnectCallback cb = L.streamConnectCallback .~ Just cb +-- | Install a callback in the provided configuration which is called+-- on HTTP 5xx errors. This allows the user to act on such error+-- conditions by e.g. logging errors or updating metrics. Note that+-- this callback is called synchronously, thus blocking in this+-- callback delays potential retry attempts.+setHttpErrorCallback :: HttpErrorCallback -> Config -> Config+setHttpErrorCallback cb = L.httpErrorCallback .~ Just cb+ -- | Install a logger callback in the provided configuration. setLogFunc :: LogFunc -> Config -> Config setLogFunc logFunc = L.logFunc .~ Just logFunc@@ -82,6 +103,11 @@ -- | Set a custom retry policy in the provided configuration. setRetryPolicy :: RetryPolicyM IO -> Config -> Config setRetryPolicy = (L.retryPolicy .~)++-- | Set a custom HTTP Backend in the provided configuration. Can be+-- used for testing.+setHttpBackend :: HttpBackend -> Config -> Config+setHttpBackend = (L.http .~)  -- | Default parameters for event consumption. defaultConsumeParameters :: ConsumeParameters
src/Network/Nakadi/Internal/Http.hs view
@@ -50,7 +50,10 @@ import qualified Data.ByteString.Lazy            as ByteString.Lazy import qualified Data.Conduit.Binary             as Conduit import qualified Data.Text                       as Text-import           Network.HTTP.Client             (responseClose, responseOpen)+import           Network.HTTP.Client             (BodyReader,+                                                  HttpException (..),+                                                  HttpExceptionContent (..),+                                                  checkResponse, responseStatus) import           Network.HTTP.Client.Conduit     (bodyReaderSource) import           Network.HTTP.Simple import           Network.HTTP.Types@@ -74,15 +77,29 @@     where callback = fromMaybe dummyCallback _deserializationFailureCallback           dummyCallback _ _ = return () +-- | Throw 'HttpException' exception on server errors (5xx).+checkNakadiResponse :: Request -> Response BodyReader -> IO ()+checkNakadiResponse request response =+  when (statusCode (responseStatus response) `div` 100 == 5) $+  throwIO $ HttpExceptionRequest request (StatusCodeException (void response) mempty)+ httpBuildRequest ::   (MonadIO m, MonadCatch m)   => Config -- ^ Configuration, contains the impure request modifier   -> (Request -> Request) -- ^ Pure request modifier-  -> m Request -- ^ Resulting request to excecute-httpBuildRequest Config { .. } requestDef = do+  -> m Request -- ^ Resulting request to execute+httpBuildRequest Config { .. } requestDef =   let manager = _manager-      request = requestDef _requestTemplate & setRequestManager manager-  tryAny (liftIO (_requestModifier request)) >>= \case+      request = requestDef _requestTemplate+                   & setRequestManager manager+                   & (\req -> req { checkResponse = checkNakadiResponse })+  in modifyRequest _requestModifier request+++-- | Modify the Request based on a user function in the configuration.+modifyRequest :: (MonadIO m, MonadCatch m) => (Request -> IO Request) -> Request -> m Request+modifyRequest rm request =+  tryAny (liftIO (rm request)) >>= \case     Right modifiedRequest -> return modifiedRequest     Left  exn             -> throwIO $ RequestModificationException exn @@ -93,9 +110,9 @@   => Config   -> (Request -> Request)   -> m (Response ByteString.Lazy.ByteString)-httpExecRequest config requestDef =-  httpBuildRequest config requestDef-  >>= (retryAction undefined . (liftIO . httpLbs))+httpExecRequest config requestDef = do+  req <- httpBuildRequest config requestDef+  retryAction config req (liftIO . (config^.L.http.L.httpLbs))  -- | Executes an HTTP request using the provided configuration and a -- pure request modifier. Returns the HTTP response and separately the@@ -150,10 +167,12 @@   -> (Request -> Request)   -> m (b, ConduitM () a (ReaderT r m) ()) httpJsonBodyStream config successStatus f exceptionMap requestDef = do-  let manager        = config^.L.manager-      request        = requestDef (config^.L.requestTemplate)-                       & setRequestManager manager-  (_, response) <- allocate (retryAction config (responseOpen request manager)) responseClose+  request <- httpBuildRequest config requestDef+  let manager           = config^.L.manager+      responseOpen      = config^.L.http.L.responseOpen+      responseClose     = config^.L.http.L.responseClose+      responseOpenRetry = retryAction config request (flip responseOpen manager)+  (_, response) <- allocate responseOpenRetry responseClose   let response_  = void response       bodySource = bodyReaderSource (getResponseBody response)       status     = getResponseStatus response
src/Network/Nakadi/Internal/Lenses.hs view
@@ -37,11 +37,13 @@   nakadiConfig :: Lens' s a  makeNakadiLenses ''Config+makeNakadiLenses ''HttpBackend makeNakadiLenses ''Cursor makeNakadiLenses ''EventStreamBatch makeNakadiLenses ''SubscriptionEventStreamBatch makeNakadiLenses ''Event makeNakadiLenses ''Metadata+makeNakadiLenses ''MetadataEnriched makeNakadiLenses ''Partition makeNakadiLenses ''CursorDistanceQuery makeNakadiLenses ''CursorDistanceResult
src/Network/Nakadi/Internal/Prelude.hs view
@@ -25,6 +25,8 @@   , encodeUtf8   , decodeUtf8   , identity+  , undefined+  , error   , MonadIO   , Request   , Response@@ -43,10 +45,19 @@ import qualified Data.Text                  as Text import           Data.Text.Encoding import           Network.HTTP.Client        (Request, Response)-import           Prelude                    hiding (id)+import           Prelude                    hiding (id, undefined, error)+import qualified Prelude  tshow :: Show a => a -> Text tshow = Text.pack . show  identity :: a -> a identity x = x++{-# WARNING undefined "usage of 'undefined' forbidden" #-}+undefined :: a+undefined = Prelude.undefined++{-# WARNING error "usage of 'error' forbidden" #-}+error :: String -> a+error = Prelude.error
src/Network/Nakadi/Internal/Retry.hs view
@@ -11,10 +11,11 @@ -}  {-# LANGUAGE LambdaCase          #-}-{-# LANGUAGE RecordWildCards     #-} {-# LANGUAGE ScopedTypeVariables #-} -module Network.Nakadi.Internal.Retry where+module Network.Nakadi.Internal.Retry+  ( retryAction+  ) where  import           Network.Nakadi.Internal.Prelude @@ -26,37 +27,54 @@ import qualified Network.Nakadi.Internal.Lenses  as L import           Network.Nakadi.Internal.Types +-- | Invokes the HTTP Error Callback set in the configuration for the+-- provided 'Request', 'HttpException' and 'RetryStatus'. If no+-- callback is set, this is no-op.+invokeHttpErrorCallback :: MonadIO m => Config -> Request -> HttpException -> RetryStatus -> m ()+invokeHttpErrorCallback config req exn retryStatus = liftIO $+  case config^.L.httpErrorCallback of+    Just cb -> do+      finalFailure <- applyPolicy (config^.L.retryPolicy) retryStatus >>= \case+        Just _  -> pure False+        Nothing -> pure True+      cb req exn retryStatus finalFailure+    Nothing -> pure ()+ -- | Try to execute the provided IO action using the provided retry -- policy. If executing the IO action raises specific exceptions of -- type 'HttpException', the action will be potentially retried -- (depending on the retry policy).-retryAction' :: (MonadIO m, MonadMask m) => RetryPolicyM IO -> m a -> m a-retryAction' policy ma =-  let nakadiRetryPolicy = RetryPolicyM $ \retryStatus ->+retryAction ::+  (MonadIO m, MonadMask m)+  => Config+  -> Request+  -> (Request -> m a)+  -> m a+retryAction config req ma =+  let policy = config^.L.retryPolicy+      nakadiRetryPolicy = RetryPolicyM $ \retryStatus ->         liftIO (getRetryPolicyM policy retryStatus)-      handlerHttpWrapped = const $ Handler handlerHttp-  in recovering nakadiRetryPolicy [handlerHttpWrapped] (const ma)+  in recovering nakadiRetryPolicy [handlerHttp] (const (ma req)) -  where handlerHttp (HttpExceptionRequest _ exceptionContent) =+  where handlerHttp retryStatus = Handler $ \exn -> do+          invokeHttpErrorCallback config req exn retryStatus+          pure $ shouldRetry exn++        shouldRetry (HttpExceptionRequest _ exceptionContent) =           case exceptionContent of             StatusCodeException response _ ->-              return $ responseStatus response `elem` [status500, status503]+              responseStatus response `elem` [status500, status503]             ResponseTimeout ->-              return True+              True             ConnectionTimeout ->-              return True+              True             ConnectionFailure _ ->-              return True+              True             InternalException _ ->-              return True+              True             ConnectionClosed ->-              return True+              True             _ ->-              return False--        handlerHttp _ = return False+              False --- | Try to execute the provided IO action, using the retry policy--- from the provided configuration.-retryAction :: (MonadIO m, MonadMask m) => Config -> m a -> m a-retryAction config = retryAction' (config^.L.retryPolicy)+        shouldRetry _ = False
src/Network/Nakadi/Internal/Types/Config.hs view
@@ -10,6 +10,8 @@ Internal configuration specific types. -} +{-# LANGUAGE StrictData #-}+ module Network.Nakadi.Internal.Types.Config where  import           Network.Nakadi.Internal.Prelude@@ -17,12 +19,17 @@ import           Control.Retry import           Network.HTTP.Client +import qualified Data.ByteString.Lazy            as LB (ByteString) import           Network.Nakadi.Types.Logger  -- | Config  type StreamConnectCallback = Maybe LogFunc -> Response () -> IO () +-- | Type synonym for user-provided callbacks which are used for HTTP+-- Errror propagation.+type HttpErrorCallback = Request -> HttpException -> RetryStatus -> Bool -> IO ()+ data Config = Config   { _requestTemplate                :: Request   , _requestModifier                :: Request -> IO Request@@ -32,6 +39,17 @@   , _streamConnectCallback          :: Maybe StreamConnectCallback   , _logFunc                        :: Maybe LogFunc   , _retryPolicy                    :: RetryPolicyM IO+  , _http                           :: HttpBackend+  , _httpErrorCallback              :: Maybe HttpErrorCallback+  }++-- | Type encapsulating the HTTP backend functions used by this+-- package. By default the corresponding functions from the+-- http-client package are used. Useful, for e.g., testing.+data HttpBackend = HttpBackend+  { _httpLbs       :: Request -> IO (Response LB.ByteString)+  , _responseOpen  :: Request -> Manager -> IO (Response BodyReader)+  , _responseClose :: Response BodyReader -> IO ()   }  -- | ConsumeParameters
src/Network/Nakadi/Internal/Types/Exceptions.hs view
@@ -10,6 +10,8 @@ Nakadi client exceptions. -} +{-# LANGUAGE StrictData #-}+ module Network.Nakadi.Internal.Types.Exceptions where  import           Network.Nakadi.Internal.Prelude@@ -31,7 +33,7 @@                      | TooManyRequests Problem                      | BadRequest Problem                      | SubscriptionNotFound Problem-                     | CursorAlreadyCommitted [CursorCommitResult]+                     | CursorAlreadyCommitted CursorCommitResults                      | CursorResetInProgress Problem                      | EventTypeNotFound Problem                      | SubscriptionExistsAlready Subscription
src/Network/Nakadi/Internal/Types/Problem.hs view
@@ -13,6 +13,7 @@ {-# LANGUAGE ApplicativeDo   #-} {-# LANGUAGE DeriveGeneric   #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE StrictData      #-} {-# LANGUAGE TupleSections   #-}  module Network.Nakadi.Internal.Types.Problem where
src/Network/Nakadi/Internal/Types/Service.hs view
@@ -14,6 +14,7 @@ {-# LANGUAGE DeriveGeneric         #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE LambdaCase            #-}+{-# LANGUAGE StrictData            #-} {-# LANGUAGE TemplateHaskell       #-}  module Network.Nakadi.Internal.Types.Service where@@ -219,13 +220,25 @@   parseJSON (String s) = return $ FlowId s   parseJSON invalid    = typeMismatch "FlowId" invalid +-- | ID of an Event++newtype EventId = EventId+  { unEventId :: UUID -- ^ Wrapped UUID+  } deriving (Show, Eq, Ord, Generic, Hashable)++instance ToJSON EventId where+  toJSON = String . tshow . unEventId++instance FromJSON EventId where+  parseJSON = parseUUID "EventId" EventId+ -- | Metadata  data Metadata = Metadata-  { _eid        :: Text -- ^ Event ID+  { _eid        :: EventId -- ^ Event ID   , _occurredAt :: Timestamp -- ^ Occurred-At timestamp-  , _parentEids :: Maybe [Text] -- ^ Event IDs of the Events which triggered this event-  , _partition  :: Maybe Text -- ^ Partition on which this Event is stored+  , _parentEids :: Maybe [EventId] -- ^ Event IDs of the Events which triggered this event+  , _partition  :: Maybe PartitionName -- ^ Partition on which this Event is stored   } deriving (Eq, Show, Generic)  deriveJSON nakadiJsonOptions ''Metadata@@ -242,36 +255,6 @@  deriveJSON nakadiJsonOptions ''Event --- | EventStreamBatch--data EventStreamBatch a = EventStreamBatch-  { _cursor :: Cursor -- ^ Cursor for this batch-  , _events :: Maybe (Vector (Event a)) -- ^ Events in this batch-  } deriving (Show, Generic)--deriveJSON nakadiJsonOptions ''EventStreamBatch---- | SubscriptionEventStreamBatch--data SubscriptionEventStreamBatch a = SubscriptionEventStreamBatch-  { _cursor :: SubscriptionCursor -- ^ cursor for this subscription batch-  , _events :: Maybe (Vector (Event a)) -- ^ Events for this subscription batch-  } deriving (Show, Generic)--deriveJSON nakadiJsonOptions ''SubscriptionEventStreamBatch---- | ID of an Event--newtype EventId = EventId-  { unEventId :: UUID -- ^ Wrapped UUID-  } deriving (Show, Eq, Ord, Generic, Hashable)--instance ToJSON EventId where-  toJSON = String . tshow . unEventId--instance FromJSON EventId where-  parseJSON = parseUUID "EventId" EventId- -- | Partition Data  data Partition = Partition@@ -453,6 +436,12 @@  deriveJSON nakadiJsonOptions ''CursorCommitResult +newtype CursorCommitResults = CursorCommitResults+  { _items :: [CursorCommitResult]+  } deriving (Show, Eq, Ord)++deriveJSON nakadiJsonOptions ''CursorCommitResults+ -- | SchemaType  data SchemaType = SchemaTypeJson@@ -735,12 +724,14 @@ -- | Type of enriched metadata values.  data MetadataEnriched = MetadataEnriched-  { _eid        :: Text+  { _eid        :: EventId   , _eventType  :: EventTypeName   , _occurredAt :: Timestamp   , _receivedAt :: Timestamp   , _version    :: SchemaVersion-  , _parentEids :: Maybe [Text]+  , _parentEids :: Maybe [EventId]+  , _flowId     :: Maybe FlowId+  , _partition  :: Maybe PartitionName   } deriving (Eq, Show, Generic)  deriveJSON nakadiJsonOptions ''MetadataEnriched@@ -759,6 +750,23 @@                                         , ("_metadata", "metadata") ]   }  ''EventEnriched +-- | EventStreamBatch++data EventStreamBatch a = EventStreamBatch+  { _cursor :: Cursor -- ^ Cursor for this batch+  , _events :: Maybe (Vector (EventEnriched a)) -- ^ Events in this batch+  } deriving (Show, Generic)++deriveJSON nakadiJsonOptions ''EventStreamBatch++-- | SubscriptionEventStreamBatch++data SubscriptionEventStreamBatch a = SubscriptionEventStreamBatch+  { _cursor :: SubscriptionCursor -- ^ cursor for this subscription batch+  , _events :: Maybe (Vector (EventEnriched a)) -- ^ Events for this subscription batch+  } deriving (Show, Generic)++deriveJSON nakadiJsonOptions ''SubscriptionEventStreamBatch  -- | Type for "data_op" as contained in the DataChangeEvent. 
src/Network/Nakadi/Internal/Types/Subscription.hs view
@@ -11,6 +11,8 @@ Service API but custom to this package. -} +{-# LANGUAGE StrictData #-}+ module Network.Nakadi.Internal.Types.Subscription where  import           Network.Nakadi.Internal.Types.Config
src/Network/Nakadi/Subscriptions/Events.hs view
@@ -59,7 +59,7 @@   let consumeParams = fromMaybe (config^.L.consumeParameters) maybeParams       queryParams = buildSubscriptionConsumeQueryParameters consumeParams -      addFlowId     = case _flowId consumeParams of+      addFlowId     = case consumeParams^.L.flowId of                         Just flowId -> setRequestHeader "X-Flow-Id" [encodeUtf8 flowId]                         Nothing     -> identity   httpJsonBodyStream config ok200 buildSubscriptionEventStream@@ -122,8 +122,8 @@   -> ConduitM ()               Void               (ReaderT SubscriptionEventStreamContext m)-              r              -- ^ Subscription Conduit to run-  -> m r                     -- ^ Result of the Conduit+              s              -- ^ Subscription Conduit to run+  -> m s                     -- ^ Result of the Conduit runSubscriptionR subscriptionEventStream conduit = do   config <- asks (view L.nakadiConfig)   runSubscription config subscriptionEventStream conduit
src/Network/Nakadi/Types/Config.hs view
@@ -12,6 +12,7 @@  module Network.Nakadi.Types.Config   ( Config+  , HttpBackend(..)   , ConsumeParameters   , StreamConnectCallback   ) where
src/Network/Nakadi/Types/Service.hs view
@@ -45,6 +45,7 @@   , BatchFlushTimeout(..)   , CursorCommitResultType(..)   , CursorCommitResult(..)+  , CursorCommitResults(..)   , SchemaType(..)   , EventTypeSchema(..)   , PaginationLink(..)
src/Network/Nakadi/Types/Subscription.hs view
@@ -11,7 +11,7 @@ -}  module Network.Nakadi.Types.Subscription-  ( SubscriptionEventStreamContext+  ( SubscriptionEventStreamContext(..)   ) where  import           Network.Nakadi.Internal.Types.Subscription
+ tests/Network/Nakadi/Config/Test.hs view
@@ -0,0 +1,48 @@+module Network.Nakadi.Config.Test where++import           ClassyPrelude+import           Control.Lens         ((<&>))+import           Control.Retry+import qualified Data.ByteString.Lazy as LB+import           Network.HTTP.Client+import           Network.Nakadi+import           System.IO.Unsafe+import           Test.Tasty+import           Test.Tasty.HUnit++testConfig :: TestTree+testConfig = testGroup "Config"+  [ testCase "Use Custom HttpBackend" testCustomHttpBackend ]++{-# NOINLINE requestsExecuted #-}+requestsExecuted :: TVar [Request]+requestsExecuted = unsafePerformIO . newTVarIO $ []++dummyHttpLbs :: Request -> IO (Response LB.ByteString)+dummyHttpLbs req = do+  atomically $ modifyTVar requestsExecuted (req :)+  throwIO (HttpExceptionRequest req ResponseTimeout)++dummyResponseOpen :: Request -> Manager -> IO (Response (IO ByteString))+dummyResponseOpen req _manager = do+  atomically $ modifyTVar requestsExecuted (req :)+  throwIO (HttpExceptionRequest req ResponseTimeout)++dummyResponseClose :: Response BodyReader -> IO ()+dummyResponseClose _response = return ()++dummyHttpBackend :: HttpBackend+dummyHttpBackend = HttpBackend dummyHttpLbs dummyResponseOpen dummyResponseClose++testCustomHttpBackend :: Assertion+testCustomHttpBackend = do+  let trivialRetryPolicy = limitRetries 0+  conf <- newConfig Nothing defaultRequest+          <&> setHttpBackend dummyHttpBackend+          <&> setRetryPolicy trivialRetryPolicy+  res0 <- try $ registryPartitionStrategies conf -- This should use httpLbs+  case res0 of+    Left (HttpExceptionRequest _ ResponseTimeout) -> return ()+    _ -> assertFailure "Expected ResponseTimeout exception from dummy HttpBackend"+  requests <- atomically . readTVar $ requestsExecuted+  1 @=? length requests
+ tests/Network/Nakadi/Connection/Test.hs view
@@ -0,0 +1,93 @@+module Network.Nakadi.Connection.Test where++import           ClassyPrelude+import           Network.HTTP.Client      (HttpException (..),+                                           HttpExceptionContent (..),+                                           Request (..), parseRequest,+                                           responseTimeoutMicro)+import           Network.HTTP.Types+import           Network.Nakadi+import qualified Network.Wai              as Wai+import           Network.Wai.Handler.Warp+import           System.IO.Unsafe+import           Test.Tasty+import           Test.Tasty.HUnit++testConnection :: TestTree+testConnection = testGroup "Connection"+  [ testCase "SimpleRetry" testSimpleRetry+  , testCase "ResponseTimeout Success" testResponseTimeoutSuccess+  , testCase "ResponseTimeout Fail" testResponseTimeoutFail+  ]++{-# NOINLINE requestCounter #-}+requestCounter :: TVar Int+requestCounter = unsafePerformIO $ newTVarIO 0++testServerRetryPort :: Port+testServerRetryPort = 5001++testServerResponseTimeoutPort :: Port+testServerResponseTimeoutPort = 5002++{-# NOINLINE testServerRequest #-}+testServerRequest :: Request+testServerRequest = unsafePerformIO $ parseRequest "http://localhost"++testServerRetryApp ::+  Int+  -> Wai.Request+  -> (Wai.Response -> IO Wai.ResponseReceived)+  -> IO Wai.ResponseReceived+testServerRetryApp noOfFailures req respond =+  case Wai.rawPathInfo req of+    "/event-types" -> do+      reqIdx <- atomically $ do+        modifyTVar requestCounter (+ 1)+        readTVar requestCounter+      let response = if reqIdx <= noOfFailures+                     then Wai.responseLBS status503 [] ""+                     else Wai.responseLBS status200 [] "[]"+      respond response+    _ ->+      respond $ Wai.responseLBS status404 [] ""++testServerResponseTimeoutApp ::+  Wai.Request+  -> (Wai.Response -> IO Wai.ResponseReceived)+  -> IO Wai.ResponseReceived+testServerResponseTimeoutApp req respond =+  case Wai.rawPathInfo req of+    "/event-types" -> do+      threadDelay (4 * 10^6) -- Wait for 4s+      respond $ Wai.responseLBS status200 [] "[]"+    _ ->+      respond $ Wai.responseLBS status404 [] ""++testSimpleRetry :: Assertion+testSimpleRetry = do+  conf <- newConfig Nothing testServerRequest { port = testServerRetryPort }+  withAsync (run testServerRetryPort (testServerRetryApp 2)) $ \_serverHandle -> do+    events <- eventTypesList conf+    [] @=? events++testResponseTimeoutSuccess :: Assertion+testResponseTimeoutSuccess = do+  let timeout = responseTimeoutMicro (5 * 10^6) -- Accept delay of 5s+  conf <- newConfig Nothing testServerRequest { port = testServerResponseTimeoutPort+                                              , responseTimeout = timeout }+  withAsync (run testServerResponseTimeoutPort testServerResponseTimeoutApp) $ \_serverHandle -> do+    events <- eventTypesList conf+    [] @=? events++testResponseTimeoutFail :: Assertion+testResponseTimeoutFail = do+  res <- try $ do+    let timeout = responseTimeoutMicro (3 * 10^6) -- Accept delay of 3s+    conf <- newConfig Nothing testServerRequest { port = testServerResponseTimeoutPort+                                                , responseTimeout = timeout }+    withAsync (run testServerResponseTimeoutPort testServerResponseTimeoutApp) $ \_serverHandle -> do+      eventTypesList conf+  case res of+    Left (HttpExceptionRequest _request ResponseTimeout) -> return ()+    _ -> assertFailure "Expected HttpExceptionRequest with content ResponseTimeout"
tests/Network/Nakadi/EventTypes/CursorsLag/Test.hs view
@@ -36,7 +36,7 @@ testCursorsLagN :: Config -> Int64 -> Assertion testCursorsLagN conf n = do   now <- getCurrentTime-  eid <- tshow <$> genRandomUUID+  eid <- EventId <$> genRandomUUID   recreateEvent conf myEventTypeName myEventType   partitions <- eventTypePartitions conf myEventTypeName   let cursorsMap = Map.fromList $
tests/Network/Nakadi/EventTypes/ShiftedCursors/Test.hs view
@@ -10,9 +10,6 @@  import           ClassyPrelude -import           Conduit-import           Control.Concurrent.Async    (link)-import           Data.Function               ((&)) import           Network.Nakadi import           Network.Nakadi.Tests.Common import           Test.Tasty@@ -35,7 +32,7 @@ testShiftedCursorsN :: Config -> Int64 -> Assertion testShiftedCursorsN conf n = do   now <- getCurrentTime-  eid <- tshow <$> genRandomUUID+  eid <- EventId <$> genRandomUUID   recreateEvent conf myEventTypeName myEventType   partitions <- eventTypePartitions conf myEventTypeName   let cursors = map extractCursor partitions
tests/Network/Nakadi/EventTypes/Test.hs view
@@ -32,6 +32,7 @@   , testCase "EventTypeCursorDistances0" (testEventTypeCursorDistances0 conf)   , testCase "EventTypeCursorDistances10" (testEventTypeCursorDistances10 conf)   , testCase "EventTypePublishData" (testEventTypePublishData conf)+  , testCase "EventTypeParseFlowId" (testEventTypeParseFlowId conf)   , testCase "EventTypeDeserializationFailure" (testEventTypeDeserializationFailure conf)   , testEventTypesShiftedCursors conf   , testEventTypesCursorsLag conf@@ -84,7 +85,7 @@    forM_ [1..10] $ \_ -> do     now <- getCurrentTime-    eid <- tshow <$> genRandomUUID+    eid <- EventId <$> genRandomUUID     eventPublish conf myEventTypeName Nothing [myDataChangeEvent eid now]    cursorPairs <- forM cursors $ \cursor@Cursor { .. } -> do@@ -106,7 +107,7 @@ testEventTypePublishData :: Config -> Assertion testEventTypePublishData conf = do   now <- getCurrentTime-  eid <- tshow <$> genRandomUUID+  eid <- EventId <$> genRandomUUID   eventTypeDelete conf myEventTypeName `catch` (ignoreExnNotFound ())   eventTypeCreate conf myEventType   let event = DataChangeEvent { _payload = Foo "Hello!"@@ -118,21 +119,49 @@                               , _dataType = "test.FOO"                               , _dataOp = DataOpUpdate                               }-  withAsync (delayedPublish [event]) $ \asyncHandle -> do+  withAsync (delayedPublish conf Nothing [event]) $ \asyncHandle -> do     link asyncHandle     eventConsumed :: Maybe (EventStreamBatch Foo) <- runResourceT $ do       source <- eventSource conf (Just consumeParametersSingle) myEventTypeName Nothing       runConduit $ source .| headC     isJust eventConsumed @=? True -  where delayedPublish events = do-          threadDelay (10^6)-          eventPublish conf myEventTypeName Nothing events+testEventTypeParseFlowId :: Config -> Assertion+testEventTypeParseFlowId conf = do+  now <- getCurrentTime+  eid <- EventId <$> genRandomUUID+  eventTypeDelete conf myEventTypeName `catch` (ignoreExnNotFound ())+  eventTypeCreate conf myEventType+  let event = DataChangeEvent { _payload = Foo "Hello!"+                              , _metadata = Metadata { _eid = eid+                                                     , _occurredAt = Timestamp now+                                                     , _parentEids = Nothing+                                                     , _partition = Nothing+                                                     }+                              , _dataType = "test.FOO"+                              , _dataOp = DataOpUpdate+                              }+      expectedFlowId = Just $ FlowId "12345"+  withAsync (delayedPublish conf expectedFlowId [event]) $ \asyncHandle -> do+    link asyncHandle+    eventConsumed :: Maybe (EventStreamBatch Foo) <- runResourceT $ do+      source <- eventSource conf (Just consumeParametersSingle) myEventTypeName Nothing+      runConduit $ source .| headC+    isJust eventConsumed @=? True+    let events = eventConsumed >>= (\batch -> batch^.L.events)+    isJust events @=? True +    case events of+      Nothing -> assertFailure "Received no events"+      Just v -> case toList v of+        [EventEnriched _ x] ->+          x^.L.flowId @=? expectedFlowId+        _ -> assertFailure "Received not a singleton event list"+ testEventTypeDeserializationFailure :: Config -> Assertion testEventTypeDeserializationFailure conf' = do   now <- getCurrentTime-  eid <- tshow <$> genRandomUUID+  eid <- EventId <$> genRandomUUID   eventTypeDelete conf myEventTypeName `catch` (ignoreExnNotFound ())   eventTypeCreate conf myEventType   let event = DataChangeEvent { _payload = Foo "Hello!"@@ -144,7 +173,7 @@                               , _dataType = "test.FOO"                               , _dataOp = DataOpUpdate                               }-  withAsync (delayedPublish [event]) $ \asyncHandle -> do+  withAsync (delayedPublish conf Nothing [event]) $ \asyncHandle -> do     link asyncHandle     eventConsumed :: Maybe (EventStreamBatch WrongFoo) <- runResourceT $ do       source <- eventSource conf (Just consumeParametersSingle) myEventTypeName Nothing@@ -154,14 +183,10 @@   counter <- atomically $ readTVar deserializationFailureCounter   1 @=? counter -  where delayedPublish events = do-          threadDelay (10^6)-          eventPublish conf myEventTypeName Nothing events--        conf = conf'+  where conf = conf'                & setDeserializationFailureCallback (deserializationFailureCb deserializationFailureCounter) -        deserializationFailureCb counter _ errMsg = do+        deserializationFailureCb counter _ _ =           atomically $ modifyTVar counter (+ 1)          deserializationFailureCounter = unsafePerformIO $ newTVarIO 0
+ tests/Network/Nakadi/Internal/Http/Test.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE ScopedTypeVariables   #-}+{-# LANGUAGE RecordWildCards       #-}++module Network.Nakadi.Internal.Http.Test+  ( testHttp+  ) where++import           Network.HTTP.Client+import           Network.HTTP.Types+import           Test.Tasty+import           Test.Tasty.HUnit+import           Control.Monad+import           Control.Monad.Reader+import           ClassyPrelude+import           Network.Nakadi.Internal.Http+import           Network.HTTP.Client.Internal (CookieJar (..), Request(..), Response (..), ResponseClose (..))+import           Network.Nakadi+import           Conduit++testHttp :: TestTree+testHttp = testGroup "Http"+  [ testCase "HttpRequestModifier" testHttpRequestModifier+  ]++resp :: Response (IO ByteString)+resp = Response+    { responseStatus = status200+    , responseVersion = http11+    , responseHeaders = []+    , responseBody = pure ""+    , responseCookieJar = CJ []+    , responseClose' = ResponseClose (pure ())+    }++headers :: RequestHeaders+headers = [("test-header", "header-value")]++dummyResponseOpen :: Request -> Manager -> IO (Response (IO ByteString))+dummyResponseOpen Request { .. } _ = do+  requestHeaders @=? headers+  pure resp++dummyHttpBackend :: HttpBackend+dummyHttpBackend = defaultHttpBackend {+    _responseOpen = dummyResponseOpen+}++dummyRequestModifier :: Request -> IO Request+dummyRequestModifier request = pure (request { requestHeaders = headers })++testHttpRequestModifier :: Assertion+testHttpRequestModifier = do+    conf <- newConfig Nothing defaultRequest+    let config = conf {_http = dummyHttpBackend, _requestModifier = dummyRequestModifier }+    (_, source) <- runResourceT $ httpJsonBodyStream config ok200 (const (Right ())) [] id+    (_ :: Maybe Text) <- runResourceT $ runReaderT (runConduit $ source .| headC) ()+    return ()
+ tests/Network/Nakadi/Internal/Retry/Test.hs view
@@ -0,0 +1,104 @@+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Network.Nakadi.Internal.Retry.Test+  ( testRetry+  ) where++import           ClassyPrelude+import           Control.Lens+import           Control.Retry+import qualified Data.ByteString.Lazy          as LB+import           Network.HTTP.Client+import           Network.HTTP.Client.Internal  (CookieJar (..), Request (..),+                                                Response (..),+                                                ResponseClose (..))+import           Network.HTTP.Types+import           Network.Nakadi+import           Network.Nakadi.Internal.Retry+import           Test.Tasty+import           Test.Tasty.HUnit++testRetry :: TestTree+testRetry = testGroup "Retry"+  [ testCase "HttpErrorCallback not called on success" testHttpErrorCallback0+  , testCase "HttpErrorCallback called on failure (n = 1)" testHttpErrorCallback1+  , testCase "HttpErrorCallback called on failure (n = maxRetries)" testHttpErrorCallbackMax+  , testCase "HttpErrorCallback called on failure (n = maxRetries + 1)" testHttpErrorCallbackMaxPlusOne+  ]++prepareMockResponse ::+  Monoid a+  => Int -- ^ Fail this many times prior to success+  -> IO (IO (Response a))+prepareMockResponse successNum = do+  counter <- newTVarIO 0+  return $ do+    current <- atomically $ do+      n <- readTVar counter+      modifyTVar counter (+ 1)+      return n+    if current >= successNum+    then return responseSuccess+    else throwM (HttpExceptionRequest defaultRequest (StatusCodeException responseFailure mempty))++  where responseTemplate = Response+          { responseStatus    = status200+          , responseVersion   = http11+          , responseHeaders   = []+          , responseBody      = mempty+          , responseCookieJar = CJ []+          , responseClose'    = ResponseClose (pure ())+          }+        responseSuccess = responseTemplate+        responseFailure = void $ responseTemplate { responseStatus = status503 }++maxRetries :: Int+maxRetries = 7++httpErrorCallback :: TVar Int -> Request -> HttpException -> RetryStatus -> Bool -> IO ()+httpErrorCallback tvCounter _request _exn _retryStatus finalFailure = do+  current <- atomically $ do+    n <- readTVar tvCounter+    modifyTVar tvCounter (+ 1)+    return n+  if current == maxRetries+     then True @=? finalFailure+     else False @=? finalFailure++mockHttpBackend :: Int -> IO HttpBackend+mockHttpBackend numFailures = do+  responder <- prepareMockResponse numFailures+  return HttpBackend+    { _httpLbs       = mockHttpLbs responder+    , _responseOpen  = responseOpen+    , _responseClose = responseClose+    }++    where mockHttpLbs responder _request = responder++-- | Tests that the callback is called exactly numFailures times+-- before the request succeeds — depending on the retry policy.+testHttpErrorCallbackN :: Int -> Assertion+testHttpErrorCallbackN numFailures = do+  httpBackend <- mockHttpBackend numFailures+  counter <- newTVarIO 0+  conf <- newConfig Nothing defaultRequest+          <&> setHttpErrorCallback (httpErrorCallback counter)+          <&> setRetryPolicy (fullJitterBackoff 2 ++ limitRetries maxRetries)+  _response :: Either HttpException (Response LB.ByteString) <- try $+    retryAction conf defaultRequest (_httpLbs httpBackend)+  current <- readTVarIO counter+  numFailures @=? current++testHttpErrorCallback0 :: Assertion+testHttpErrorCallback0 = testHttpErrorCallbackN 0++testHttpErrorCallback1 :: Assertion+testHttpErrorCallback1 = testHttpErrorCallbackN 1++testHttpErrorCallbackMax :: Assertion+testHttpErrorCallbackMax = testHttpErrorCallbackN maxRetries++testHttpErrorCallbackMaxPlusOne :: Assertion+testHttpErrorCallbackMaxPlusOne = testHttpErrorCallbackN (maxRetries + 1)
+ tests/Network/Nakadi/Internal/Test.hs view
@@ -0,0 +1,13 @@+module Network.Nakadi.Internal.Test where++import           Network.Nakadi.Internal.Http.Test+import           Network.Nakadi.Internal.Retry.Test+import           Network.Nakadi.Internal.Types.Test+import           Test.Tasty++testInternal :: TestTree+testInternal = testGroup "Internal"+  [ testTypes+  , testHttp+  , testRetry+  ]
+ tests/Network/Nakadi/Internal/Types/Test.hs view
@@ -0,0 +1,23 @@+{-# LANGUAGE OverloadedStrings     #-}++module Network.Nakadi.Internal.Types.Test where++import ClassyPrelude+import Test.Tasty+import Test.Tasty.HUnit+import Data.Aeson+import Network.Nakadi.Types.Service++testTypes :: TestTree+testTypes = testGroup "Types"+  [ testService+  ]++testService :: TestTree+testService = testGroup "Service"+  [ testCase "JSON-decoding CursorCommitResults" testDecodeCursorCommitResults+  ]++testDecodeCursorCommitResults :: Assertion+testDecodeCursorCommitResults = assertBool "Failed to decode" $ isJust (decode sampleResponse :: (Maybe CursorCommitResults))+  where sampleResponse = "{\"items\":[{\"cursor\":{\"partition\":\"0\",\"offset\":\"001-0001-000000000000007598\",\"event_type\":\"http4s-nakadi.test-event\",\"cursor_token\":\"3bb3a590-ede5-43a9-981e-2bea26347c99\"},\"result\":\"outdated\"}]}"
tests/Network/Nakadi/Tests/Common.hs view
@@ -56,7 +56,7 @@   Cursor { _partition = _partition          , _offset    = _newestAvailableOffset } -myDataChangeEvent :: Text -> UTCTime -> DataChangeEvent Foo+myDataChangeEvent :: EventId -> UTCTime -> DataChangeEvent Foo myDataChangeEvent eid now =  DataChangeEvent   { _payload = Foo "Hello!"   , _metadata = Metadata { _eid        = eid@@ -75,3 +75,8 @@ recreateEvent conf eventTypeName eventType = do   eventTypeDelete conf eventTypeName `catch` (ignoreExnNotFound ())   eventTypeCreate conf eventType++delayedPublish :: (ToJSON a) => Config -> Maybe FlowId -> [a] -> IO ()+delayedPublish conf flowId events  = do+  threadDelay (10^6)+  eventPublish conf myEventTypeName flowId events
tests/Tests.hs view
@@ -1,28 +1,71 @@ import           ClassyPrelude -import           Control.Lens import           Network.HTTP.Client import           Network.Nakadi+import           Network.Nakadi.Config.Test+import           Network.Nakadi.Connection.Test import           Network.Nakadi.EventTypes.Test+import           Network.Nakadi.Internal.Test import           Network.Nakadi.Registry.Test import           Network.Nakadi.Subscriptions.Test import           System.Environment+import           System.Exit+import           System.IO                         (hFlush) import           Test.Tasty -createConfig :: IO Config-createConfig = do-  nakadiEndpoint <- fromMaybe (error "TEST_NAKADI_ENDPOINT not set") <$>-                    lookupEnv "TEST_NAKADI_ENDPOINT"-  request <- parseRequest nakadiEndpoint-  newConfig Nothing request- main :: IO () main = do-  conf <- createConfig-  defaultMain (tests conf)+  putStrLn ""+  maybeNakadiEndpoint <- lookupEnv "TEST_NAKADI_ENDPOINT"+  (label, runTests) <- case maybeNakadiEndpoint of+    Nothing -> do+      hPut stderr . encodeUtf8 $+        "***************************************************************\n\+        \** The environment variable TEST_NAKADI_ENDPOINT is not set. **\n\+        \**                                                           **\n\+        \**              SKIPPING INTEGRATION TESTS                   **\n\+        \**                                                           **\n\+        \** If you want to run the integration tests contained in     **\n\+        \** this test suite, you need to run a Nakadi server which    **\n\+        \** allows access without authentication. Then, set the       **\n\+        \** environment variable TEST_NAKADI_ENDPOINT to the base     **\n\+        \** endpoint of this Nakadi server.                           **\n\+        \**                                                           **\n\+        \** To run a local Nakadi server clone the repository         **\n\+        \**                                                           **\n\+        \**     https://github.com/zalando/nakadi                     **\n\+        \**                                                           **\n\+        \** and follow the contained instructions; the command        **\n\+        \**                                                           **\n\+        \**     ./gradlew startNakadi                                 **\n\+        \**                                                           **\n\+        \** starts a local Nakadi server at http://localhost:8080.    **\n\+        \**                                                           **\n\+        \** Thus, set TEST_NAKADI_ENDPOINT to http://localhost:8080.  **\n\+        \***************************************************************\n"+      return ("nakadi-client Test Suite (w/o integration tests)", unitTests)+    Just nakadiEndpoint -> do+      let nakadiEndpointT = pack nakadiEndpoint+      case parseRequest nakadiEndpoint of+        Just request -> do+          conf <- newConfig Nothing request+          return ("nakadi-client Test Suite", unitTests ++ integrationTests conf)+        Nothing -> do+          hPut stderr . encodeUtf8 $+            "Failed to parse Nakadi URL in TEST_NAKADI_ENDPOINT (" <> nakadiEndpointT <> ")"+          hFlush stderr+          exitFailure+  defaultMain (testGroup label runTests) -tests :: Config -> TestTree-tests conf = testGroup "Test Suite"+unitTests :: [TestTree]+unitTests =+  [ testInternal+  , testConfig+  , testConnection+  ]++integrationTests :: Config -> [TestTree]+integrationTests conf =   [ testEventTypes conf   , testRegistry conf   , testSubscriptions conf