Ga naar hoofdinhoud

Eventsysteem

Alles wat significant is, loopt asynchroon via RabbitMQ. Een trigger (API-call, scheduler, scan) roept MessageSender.send() aan, die het event naar zijn queue routeert; een Handle<T>-implementatie in disk/, worker/, search/ of transcoder/ consumeert het, doet zijn werk en kan verdere events versturen. Het volledige eventoverzicht laat zien hoe de belangrijkste triggers uitwaaieren over de handlers.

Het Handle<T>-contract

Handle<T extends MessageData> (core-module) is de centrale interface. handles() geeft het EventType terug dat de handler bezit; de standaard-listener() weigert elk bericht waarvan het eventType-veld niet overeenkomt voordat er naar handle() gedispatcht wordt. Handlers zijn gewone Spring-beans met een @RabbitListener op hun queue.

Geen Hibernate-sessie op listener-threads. RabbitMQ-listener-threads hebben geen open sessie, dus lazy navigeren over associaties gooit een LazyInitializationException. Handlers moeten wat ze nodig hebben expliciet laden met repository-queries (fetch joins of speciale finder-methodes), nooit door entity-grafen af te lopen.

Twee enums, haal ze niet door elkaar

  • EventType (database/.../enums/EventType.java) is het logische berichttype — de bron van waarheid voor welke soorten events er bestaan (31 waarden). Handle.handles() geeft er één terug.
  • MessageQueue (core/.../MessageQueue.java) bevat de basisnamen van de queues. MessageSender mapt een event naar zijn queue.

Queue-namen volgen app.ister.server.<event>[.<scope>], waarbij de scope een directorynaam of nodenaam is, of ontbreekt bij globale queues. Die scoping is wat werk routeert naar de node die de bestanden bezit: elke node declareert en beluistert alleen de queues van zijn eigen directories.

Retries en dead-lettering

Mislukte listeners proberen het opnieuw met exponentiële backoff (spring.rabbitmq.listener.simple.retry.* in core.properties: 3 pogingen, 2s beginInterval, multiplier 2). Na de laatste mislukking verplaatst een RepublishMessageRecoverer het bericht naar de app.ister.server.dead-letter-queue, met de exceptie bewaard in de message-headers (RabbitReliabilityConfig). Recente mislukkingen voeden ook de RecentFailuresBuffer voor de status-subscriptions (hoofdstuk 5). De e2e van de Helm-chart faalt op elk dead-lettered event — daarom moet elke externe call achter een configureerbare base-URL zitten.

Queue-scoping

ScopeEvents
Node .{nodeName}ANALYZE_LIBRARY_REQUEST
Directory .{dirName}NEW_DIRECTORIES_SCAN_REQUEST, FILE_SCAN_REQUESTED, MEDIA_FILE_FOUND, AUDIO_FILE_FOUND, EPUB_FILE_FOUND, COMIC_FILE_FOUND, SUBTITLE_FILE_FOUND, IMAGE_FOUND, NFO_FILE_FOUND, UPDATE_IMAGES_REQUESTED, ANALYZE_DATA (disk), PRE_TRANSCODE_RECENTLY_WATCHED, TRANSCODE_REQUESTED, TRANSCODE_PASS_REQUESTED
GlobaalSHOW_FOUND, EPISODE_FOUND, MOVIE_FOUND, PERSON_FOUND, ALBUM_FOUND, BOOK_FOUND, COMIC_SERIES_FOUND, CHAPTER_FOUND (geen consumer), PODCAST_FOUND (geen consumer), PODCAST_EPISODE_FOUND (geen consumer), PODCAST_REFRESH_REQUESTED, CONTINUE_WATCHING_REBUILD_REQUESTED, ANALYZE_DATA (worker), SEARCH_INDEX_REQUESTED, SEARCH_REINDEX_REQUESTED
Cache-directory .{nodeName}-cache-directoryPODCAST_EPISODE_DOWNLOAD_REQUESTED (de download landt op de disk van die node)

PRE_TRANSCODE_RECENTLY_WATCHED is gescoped op disknaam in plaats van directorynaam (zie TranscoderQueueNamingConfig).

Handler-referentie

HandlerModuleOntvangtVerstuurt
HandleNewDirectoriesScanRequesteddiskNEW_DIRECTORIES_SCAN_REQUESTFILE_SCAN_REQUESTED
FileScanRequestedHandlediskFILE_SCAN_REQUESTEDMEDIA_FILE_FOUND / AUDIO_FILE_FOUND / EPUB_FILE_FOUND / COMIC_FILE_FOUND / IMAGE_FOUND / NFO_FILE_FOUND / SUBTITLE_FILE_FOUND
HandleMediaFileFounddiskMEDIA_FILE_FOUNDIMAGE_FOUND
HandleAudioFileFounddiskAUDIO_FILE_FOUNDIMAGE_FOUND (track- óf chapter-gebonden, per library-type)
HandleEpubFileFounddiskEPUB_FILE_FOUNDIMAGE_FOUND
HandleComicFileFounddiskCOMIC_FILE_FOUNDIMAGE_FOUND (geëxtraheerde cover)
HandleSubtitleFileFounddiskSUBTITLE_FILE_FOUND
HandleImageFounddiskIMAGE_FOUND
HandleNfoFileFounddiskNFO_FILE_FOUND
HandleUpdateImagesRequesteddiskUPDATE_IMAGES_REQUESTEDUPDATE_IMAGES_REQUESTED (volgende chunk)
HandleAnalyzeDataDiskdiskANALYZE_DATAMEDIA_FILE_FOUND / AUDIO_FILE_FOUND / NFO_FILE_FOUND / SUBTITLE_FILE_FOUND
HandlePreTranscodeRecentlyWatcheddiskPRE_TRANSCODE_RECENTLY_WATCHEDTRANSCODE_REQUESTED, MEDIA_FILE_FOUND (voor bestanden zonder geanalyseerde streams)
HandlePersonFounddiskPERSON_FOUNDNFO_FILE_FOUND
HandleAlbumFounddiskALBUM_FOUNDNFO_FILE_FOUND
HandlePodcastEpisodeDownloadRequesteddiskPODCAST_EPISODE_DOWNLOAD_REQUESTEDAUDIO_FILE_FOUND (op de cache-dir-queue → ffprobe + HLS-pregeneratie)
AnalyzeLibraryRequestedHandleworkerANALYZE_LIBRARY_REQUESTUPDATE_IMAGES_REQUESTED, SHOW_FOUND, EPISODE_FOUND, MOVIE_FOUND, PERSON_FOUND, ALBUM_FOUND, AUDIO_FILE_FOUND
AnalyzeDataHandleworkerANALYZE_DATAcascade per entiteitstype
HandleShowFoundworkerSHOW_FOUNDIMAGE_FOUND (+ cast credits direct in de database)
HandleEpisodeFoundworkerEPISODE_FOUNDIMAGE_FOUND (+ cast/guest-star credits direct in de database)
MovieFoundHandleworkerMOVIE_FOUNDIMAGE_FOUND (+ cast credits direct in de database)
HandlePersonFoundworkerPERSON_FOUND
HandleAlbumFoundworkerALBUM_FOUNDIMAGE_FOUND
HandleBookFoundworkerBOOK_FOUNDIMAGE_FOUND (Open Library-cover, alleen als er nog geen is)
HandleComicSeriesFoundworkerCOMIC_SERIES_FOUNDIMAGE_FOUND (Wikipedia-thumbnail, alleen zonder lokale artwork)
HandlePodcastRefreshRequestedworkerPODCAST_REFRESH_REQUESTEDIMAGE_FOUND (feed-cover), PODCAST_EPISODE_FOUND, PODCAST_EPISODE_DOWNLOAD_REQUESTED (nieuwste N)
HandleContinueWatchingRebuildRequestedworkerCONTINUE_WATCHING_REBUILD_REQUESTED
HandleTranscodeRequestedtranscoderTRANSCODE_REQUESTEDTRANSCODE_PASS_REQUESTED
HandleTranscodePassRequestedtranscoderTRANSCODE_PASS_REQUESTED
HandleSearchIndexRequestedsearchSEARCH_INDEX_REQUESTED— (upsert/delete in Typesense)
HandleSearchReindexRequestedsearchSEARCH_REINDEX_REQUESTED— (volledige rebuild + alias-swap)

SEARCH_INDEX_REQUESTED wordt op veel plekken verstuurd: ServerEventService.createXFoundEvent (bij creatie), MetadataSave (TMDB), de MusicBrainz- en NFO-handlers, audio-tag-saves (inclusief action=DELETE bij track-dedup) en metadata-deletes — zie hoofdstuk 6.