{"id":20828800,"url":"https://github.com/perty/musicnerd","last_synced_at":"2025-10-17T17:26:31.472Z","repository":{"id":49781270,"uuid":"517581842","full_name":"perty/musicnerd","owner":"perty","description":"A service that collects information about an artist","archived":false,"fork":false,"pushed_at":"2022-07-26T13:13:00.000Z","size":107,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-18T18:39:31.248Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/perty.png","metadata":{"files":{"readme":"Readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-07-25T08:32:41.000Z","updated_at":"2022-07-25T08:37:05.000Z","dependencies_parsed_at":"2022-09-18T07:23:32.336Z","dependency_job_id":null,"html_url":"https://github.com/perty/musicnerd","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perty%2Fmusicnerd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perty%2Fmusicnerd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perty%2Fmusicnerd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/perty%2Fmusicnerd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/perty","download_url":"https://codeload.github.com/perty/musicnerd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243179813,"owners_count":20249179,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-17T23:18:28.032Z","updated_at":"2025-10-17T17:26:26.437Z","avatar_url":"https://github.com/perty.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Music Nerd\n\nGet that info on that artist with this remarkable service that collects data from not less than 4 services on the internet!\n\n## Linking information\n\nGiven the `MBID (MusicBrainz Identifier)` MusicNerd will collect the information from `MusicBrainz` database. From that information the `Wikidata` service is queried to get the story on `Wikipedia`.\n\nThe `MusicBrainz` response is also used to find the cover art from `Cover Art Archive` database.\n\n### Sequence diagram\n\nThe diagram illustrates the order of the service calls. Note the parallellism in the last calls. The `Wikidata` and `Wikipedia` calls are executed in parallell with the call to `Cover Art Archive`.\n\n```mermaid\nsequenceDiagram\nactor user\nparticipant MN as MusicNerd\nparticipant MB as MusicBrainz\nparticipant WD as Wikidata\nparticipant WP as Wikipedia\nparticipant CA as Cover Art Archive\nuser-\u003e\u003eMN: GET /musify/music-artist/details/{mbid} \nMN-\u003e\u003eMB: GET artist/{mbid}\nMB--\u003e\u003eMN: artist-urls\npar MusicNerd to Wikidata and Wikipedia\n    MN-\u003e\u003eWD: GET Entity data\n    WD--\u003e\u003eMN: wikipedia link\n    MN-\u003e\u003eWP: GET page/summary\n    WP--\u003e\u003eMN: summary\nand MusicNerd to Cover Art Archive\n    loop every album\n        MN-\u003e\u003eCA: GET /release-group\n        CA--\u003e\u003eMN: cover arts\n    end\nend\nMN--\u003e\u003euser: MusicNerd response\n```\n\n## Architecture\n\nThe service serves the needs of users from all over the world and needs to be there all the time. Therefore, the architecture must have the qualities to match these business goals.\n\n### Scalability\nThe service is deployed behind auto-scaling load balancer that increase and decrease the number of instances as the load varies.\n\n### Performance\nAlthough the response times depends on the services it uses, the `Cover Art Archive` service is called in parallell with `Wikidata` and `Wikipedia`. \n\n### Availability\nThe service is deployed in several availability zones across the world to ensure maximum availability.\n\nThe minimum number of instances in each zone is two, to ensure availability during maintenance.\n\n### Security\nThe correctness and availability ot the information presented by the service is depending on the services used. \n\nMusicNerd will respond with a `Gateway Timeout (504)` when any of those services is not available.\n\nAll information is public and users are anonymous.\n\n### Testability\nThe service is depending on 4 other services and those needs to be simulated in some way. \nWe use `MockWebServer` for this.\n\n### Maintainability\nThe service logs all errors and alarms are set up to monitor the logs. The alarms are sent to a dedicated Slack channel.\n\nThe service can run on a local machine and still present production data as it is public. Therefore, any issues can be examined locally.\n\n### Usability\nThe service exposes a REST API publicly which is great, from an architectural standpoint on usability.\nFrom a human user perspective, not so much.\n\n## Design choices\n\nTo create a service that is as responsive as possible, we selected [WebFlux](https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html) of [Spring boot](https://spring.io/projects/spring-boot). This is allows for \n[reactive programming](https://www.reactivemanifesto.org/), specifically for non-blocking calls. \n\nIt turns out that the time spent looking up cover art, overshadows the time used to get Wikipedia data, so the gain is \nvery small. Further investigation may reveal improvements.\n\nJava `record` was used instead of classes where fit.\n\nCode is organized after the services that are used. Each package represents a port and adapter for that service. Only necessary records and classes are declared public.\n\nThe main service depends on all four packages.\n\n### Error handling\nIt is quite common with missing cover art, see below for an example. Those are replaced with a `null` image url. The idea is that the whole request should not fail because of that.\n\nThe `exception` package contains exception mapping that maps exceptions to error status codes.\n\n## How to run the service\n\nStart the service locally from the repository root with `mvn spring-boot:run`.\n\nThe service runs at port 8080. Some requests to try:\n- http://localhost:8080/musify/music-artist/details/f27ec8db-af05-4f36-916e-3d57f91ecf5e (Michael Jackson)\n- http://localhost:8080/musify/music-artist/details/5441c29d-3602-4898-b1a1-b77fa23b8e50 (David Bowie)\n- http://localhost:8080/musify/music-artist/details/510fcf21-a1f3-40af-9087-40593af86f7f (Barns Courtney - results in a missing cover art)\n\nResponse times may be very long, about 20 seconds.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fperty%2Fmusicnerd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fperty%2Fmusicnerd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fperty%2Fmusicnerd/lists"}