github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/archive/examples/basic_replay_merge/basic_replay_merge.go (about) 1 // Copyright (C) 2021-2022 Talos, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // An example replayed subscriber 16 package main 17 18 import ( 19 "flag" 20 "fmt" 21 "time" 22 23 "github.com/lirm/aeron-go/aeron" 24 "github.com/lirm/aeron-go/aeron/atomic" 25 "github.com/lirm/aeron-go/aeron/idlestrategy" 26 "github.com/lirm/aeron-go/aeron/logbuffer" 27 "github.com/lirm/aeron-go/aeron/logging" 28 "github.com/lirm/aeron-go/archive" 29 "github.com/lirm/aeron-go/archive/codecs" 30 "github.com/lirm/aeron-go/archive/examples" 31 "github.com/lirm/aeron-go/archive/replaymerge" 32 ) 33 34 var logID = "basic_replay_merge" 35 var logger = logging.MustGetLogger(logID) 36 37 func main() { 38 flag.Parse() 39 40 sampleChannel := *examples.Config.MdcChannel 41 sampleStream := int32(*examples.Config.SampleStream) 42 responseStream := sampleStream + 2 43 44 timeout := time.Duration(time.Millisecond.Nanoseconds() * *examples.Config.DriverTimeout) 45 context := aeron.NewContext(). 46 AeronDir(*examples.Config.AeronPrefix). 47 MediaDriverTimeout(timeout). 48 AvailableImageHandler(func(image aeron.Image) { 49 logger.Infof("Image available: %+v", image) 50 }). 51 UnavailableImageHandler(func(image aeron.Image) { 52 logger.Infof("Image unavailable: %+v", image) 53 }). 54 ErrorHandler(func(err error) { 55 logger.Warning(err) 56 }) 57 58 options := archive.DefaultOptions() 59 options.RequestChannel = *examples.Config.RequestChannel 60 options.RequestStream = int32(*examples.Config.RequestStream) 61 options.ResponseChannel = *examples.Config.ResponseChannel 62 options.ResponseStream = responseStream 63 64 t := false 65 examples.Config.Verbose = &t 66 if *examples.Config.Verbose { 67 fmt.Printf("Setting loglevel: archive.DEBUG/aeron.INFO\n") 68 options.ArchiveLoglevel = logging.DEBUG 69 options.AeronLoglevel = logging.DEBUG 70 logging.SetLevel(logging.DEBUG, logID) 71 } else { 72 logging.SetLevel(logging.NOTICE, logID) 73 } 74 75 arch, err := archive.NewArchive(options, context) 76 if err != nil { 77 logger.Fatalf("Failed to connect to media driver: %s\n", err.Error()) 78 } 79 defer arch.Close() 80 81 // Enable recording events although the defaults will only log in debug mode 82 arch.EnableRecordingEvents() 83 84 recording, err := FindLatestRecording(arch, sampleChannel, sampleStream) 85 if err != nil { 86 logger.Fatalf(err.Error()) 87 } 88 89 subChannelUri, _ := aeron.ParseChannelUri("aeron:udp") 90 subChannelUri.SetControlMode(aeron.MdcControlModeManual) 91 subChannelUri.SetSessionID(recording.SessionId) 92 subChannel := subChannelUri.String() 93 94 logger.Infof("Subscribing to channel:%s, stream:%d", subChannel, sampleStream) 95 subscription, err := arch.AddSubscription(subChannel, sampleStream) 96 if err != nil { 97 logger.Fatal(err) 98 } 99 defer subscription.Close() 100 101 counter := 0 102 printHandler := func(buffer *atomic.Buffer, offset int32, length int32, header *logbuffer.Header) { 103 bytes := buffer.GetBytesArray(offset, length) 104 logger.Infof("Message: %s", bytes) 105 counter++ 106 } 107 108 idleStrategy := idlestrategy.Sleeping{SleepFor: time.Millisecond * 100} 109 110 liveDestination := sampleChannel 111 112 replayDestinationUri, _ := aeron.ParseChannelUri("aeron:udp?endpoint=localhost:0") 113 replayDestination := replayDestinationUri.String() 114 115 replayChannelUri, _ := aeron.ParseChannelUri(replayDestination) 116 replayChannelUri.SetSessionID(recording.SessionId) 117 replayChannel := replayChannelUri.String() 118 119 logger.Infof( 120 "ReplayMerge(subChannel:%s,%d,replayChannel:%s,replayDestination:%s,liveDestination:%s)", 121 subscription.Channel(), 122 subscription.StreamID(), 123 replayChannel, 124 replayDestination, 125 liveDestination, 126 ) 127 merge, err := replaymerge.NewReplayMerge( 128 subscription, 129 arch, 130 replayChannel, 131 replayDestination, 132 liveDestination, 133 recording.RecordingId, 134 0, 135 5000, 136 ) 137 if err != nil { 138 logger.Fatalf(err.Error()) 139 } 140 defer merge.Close() 141 142 var fragmentsRead int 143 for !merge.IsMerged() { 144 fragmentsRead, err = merge.Poll(printHandler, 10) 145 if err != nil { 146 logger.Fatalf(err.Error()) 147 } 148 arch.RecordingEventsPoll() 149 idleStrategy.Idle(fragmentsRead) 150 } 151 152 merge.Close() 153 154 for { 155 fragmentsRead := subscription.Poll(printHandler, 10) 156 arch.RecordingEventsPoll() 157 158 idleStrategy.Idle(fragmentsRead) 159 } 160 } 161 162 // FindLatestRecording to lookup the last recording 163 func FindLatestRecording(arch *archive.Archive, channel string, stream int32) (*codecs.RecordingDescriptor, error) { 164 descriptors, err := arch.ListRecordingsForUri(0, 100, "", stream) 165 166 if err != nil { 167 return nil, err 168 } 169 170 if len(descriptors) == 0 { 171 return nil, fmt.Errorf("no recordings found") 172 } 173 174 descriptor := descriptors[len(descriptors)-1] 175 if descriptor.StopPosition == 0 { 176 return nil, fmt.Errorf("recording length zero") 177 } 178 179 // Return the last recordingID 180 return descriptor, nil 181 }