Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(LSG): get rid of async in handlers; extract shared logic to base classes #1367

Open
wants to merge 3 commits into
base: release53
Choose a base branch
from

Conversation

ianshade
Copy link
Contributor

@ianshade ianshade commented Jan 28, 2025

About the Contributor

This pull request is posted on behalf of TV 2 Norge

Type of Contribution

This is a:

Code improvement

Current Behavior

New Behavior

  • Event handlers for document updates are no longer asynchronous, which should make the code less prone to race conditions
  • Throttling (batching) of document update events is moved to the CollectionBase class
  • Repeating collection (publication) subscription and observer setup/teardown logic is extracted to the PublicationCollection class
  • Subscription to collection handlers by other collection handlers and topics is now performed in the init methods of those handlers and topics instead of all happening in LiveStatusServer
  • Large update methods are broken down into smaller ones, per each collection (tradeoff: a little extra boilerplate, but less indentation and better type safety)
  • Subscription to collection handlers is done more selectively - only change of selected properties trigger update events
  • Some redundant properties are removed (observerName)
  • In a few cases, slight changes of which collection handlers are subscribed to in order to get certain information (rundownId)
  • Simplified the initial no-data flow and empty array handling

Testing

  • I have added one or more unit tests for this PR
  • I have updated the relevant unit tests
  • No unit test changes are needed for this PR

Affected areas

This PR affects the Live Status Gateway

Time Frame

Not urgent, but it would be nice to have in release 52

Other Information

These changes were so far tested only on release50, with release51 LSG

Status

  • PR is ready to be reviewed.
  • The functionality has been tested by the author.
  • Relevant unit tests has been added / updated.
  • Relevant documentation (code comments, system documentation) has been added / updated.

@ianshade ianshade requested a review from a team as a code owner January 28, 2025 00:42
Copy link

codecov bot commented Jan 28, 2025

Codecov Report

Attention: Patch coverage is 86.24339% with 26 lines in your changes missing coverage. Please review.

Please upload report for BASE (release53@b51ee26). Learn more about missing BASE report.

Files with missing lines Patch % Lines
...ages/live-status-gateway/src/topics/adLibsTopic.ts 75.00% 14 Missing ⚠️
...e-status-gateway/src/topics/activePlaylistTopic.ts 84.21% 9 Missing ⚠️
packages/live-status-gateway/src/wsHandler.ts 81.81% 1 Missing and 1 partial ⚠️
...es/live-status-gateway/src/topics/segmentsTopic.ts 96.42% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             release53    #1367   +/-   ##
============================================
  Coverage             ?   56.71%           
============================================
  Files                ?      397           
  Lines                ?    72363           
  Branches             ?     4389           
============================================
  Hits                 ?    41038           
  Misses               ?    31219           
  Partials             ?      106           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ianshade ianshade changed the title refactor(EAV-450): get rid of async in handlers; extract shared logic to base classes refactor(LSG): get rid of async in handlers; extract shared logic to base classes Jan 28, 2025
@nytamin nytamin added Contribution External contribution Contribution from TV 2 Norge Contributions sponsored by TV 2 Norge (tv2.no) labels Jan 29, 2025
@nytamin nytamin changed the base branch from release52 to release53 February 4, 2025 14:15
Copy link
Member

@jstarpl jstarpl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very welcome addition! I did find a couple of places where the code could be DRY'ed a bit, without a downside, I think?

}
export type ObserverCallback<T, K extends keyof T> = (data: Pick<T, K> | undefined) => void

export type PickArr<T, K extends readonly (keyof T)[]> = Pick<T, K[number]>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering the very generic nature of this Type utility, should it perhaps live outside of this source file? Maybe in shared-lib, alongside our other type utilities?

if (!col) throw new Error(`collection '${this._collectionName}' not found!`)
this._collectionData = col.find({ rundownId: this._curRundownId })
await this.notify(this._collectionData)
protected changed(): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member is protected, while a similar member in globalAdLibActionsHandler isn't. Would it make sense to standarize them?

import { RundownId } from '@sofie-automation/corelib/dist/dataModel/Ids'

const PLAYLIST_KEYS = ['currentPartInfo', 'nextPartInfo'] as const
type Playlist = PickArr<DBRundownPlaylist, typeof PLAYLIST_KEYS>

export class GlobalAdLibActionsHandler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There seems to be a set of these classes that are effectively the same implementation, just with a bunch of specific Types for members they are handling (I'm seeing AdLibsHandler, AdLibActionsHandler, GlobalAdLibActionsHandler specifically). Do you think it would make sense to make them a single implementation? I don't see much difference betwen them TBH. Maybe they could all just extend a single base class?

this.updateAndNotify()
}

protected updateAndNotify(): void {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this member protected and not private?

}
}

export abstract class PublicationCollection<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do yo think it would make sense to put thse abstract classes to files of their own? I suppose they aren't really related to the WebSocketTopicBase as such?

TPubSub extends CorelibPubSub | undefined,
TCollection extends keyof CorelibPubSubCollections
> {
export abstract class CollectionBase<T, TCollection extends keyof CorelibPubSubCollections> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize this is a refactoring of the older class, but considering PublicationCollection has now been added to this file, do you think it would make sense to move it to it's own file, to avoid it growing?

this._subscriptionPending = false
this.changed()
})
}
}

export interface Collection<T> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this should go with CollectionBase to it's own file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Contribution from TV 2 Norge Contributions sponsored by TV 2 Norge (tv2.no) Contribution External contribution
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants