{"id":19560578,"url":"https://github.com/buzzfeed/phonon","last_synced_at":"2025-04-26T23:33:15.637Z","repository":{"id":24442222,"uuid":"27844200","full_name":"buzzfeed/phonon","owner":"buzzfeed","description":"Phonon","archived":false,"fork":false,"pushed_at":"2023-08-14T21:38:03.000Z","size":490,"stargazers_count":3,"open_issues_count":3,"forks_count":2,"subscribers_count":248,"default_branch":"master","last_synced_at":"2025-04-17T01:26:52.599Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/buzzfeed.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-10T23:08:20.000Z","updated_at":"2022-05-02T15:44:17.000Z","dependencies_parsed_at":"2022-08-23T00:10:58.914Z","dependency_job_id":null,"html_url":"https://github.com/buzzfeed/phonon","commit_stats":null,"previous_names":["buzzfeed/disref"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buzzfeed%2Fphonon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buzzfeed%2Fphonon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buzzfeed%2Fphonon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buzzfeed%2Fphonon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/buzzfeed","download_url":"https://codeload.github.com/buzzfeed/phonon/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251068040,"owners_count":21531475,"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-11T05:08:05.316Z","updated_at":"2025-04-26T23:33:12.075Z","avatar_url":"https://github.com/buzzfeed.png","language":"Python","readme":"# Installation\n\nSimplest way to get the project is through the Python Package Index\n\n```\npip install phonon\n```\n\nYou can install this package pretty easily with setup.py\n\n```\npython setup.py install\n```\n\nOr you can use git+ssh to get the bleeding edge:\n\n```\npip install git+ssh://git@github.com/buzzfeed/phonon.git \n```\n\nBut you can also use pip if you clone...\n\n```\ngit clone git@github.com:buzzfeed/phonon.git ./phonon; cd phonon; pip install .\n```\n\n# Run the tests\n\nThis package uses the standard `setup.py` approach:\n\n```\npython setup.py test\n```\n\nYou should probably run that in a virtualenv. People should use virtualenvs.\n\n# Getting Started\n\nThis latest version of `phonon` encourages a lock-free, asynchronous approach to aggregation through your redis cache. \nWith this in mind; we _support_ but do not _encourage_ locking. With that said... \n\n## References\n\nThe building blocks for this approach to concurrency is the `Reference` object. You can use `Reference` s for \n\n* locking on resources for exclusive reads or writes\n* finding out how many processes are using a resource at a given time\n* keeping track of how many processes have modified that resource\n* executing a callback when a process is the last to finish using a resource\n\n### An example\n\nLet's say we have a process that monitors events on a stream in NSQ, a popular message bus. Sometimes these can be VERY high volume!\n\nIf we want to aggregate locally, before writing to a cache, and ultimately a database; `phonon` makes that process easy.\n\n```python\nimport nsq\n\nimport phonon.registry\nimport phonon.connections\nimport phonon.model\nimport phonon.field\n\nclass Session(phonon.model.Model):\n    id = phonon.field.ID()\n    impressions = phonon.field.SumField()\n    clicks = phonon.field.SumField()\n    \n    def on_complete(self, msg):\n        # Write the model to the database. You're guaranteed to have the global aggregate now.\n        msg.finish()\n    \ndef handle_message(msg):\n    msg.enable_async()\n    body = json.loads(msg.body)\n    phonon.registry.register(Session(\n        id=body['user_id'],\n        impressions=int(body['type'] == 'unit_impression'),\n        clicks=int(body['type'] == 'unit_click', msg)\n\nif __name__ == '__main__':\n    phonon.connections.connect(hosts=['redis01.example.com', 'redis02.example.com'])\n    nsq.Reader(\n        topic=CONVERSION_EVENTS_TOPIC,\n        channel=QR_CLICKS_AND_IMPRESSIONS_AGGREGATOR,\n        message_handler=handle_message,\n        lookupd_http_addresses=['nsq01.example.com', 'nsq02.example.com'],\n        max_in_flight=10\n    )\n    nsq.run()\n    \n```\n\nBy declaring a session with the `SumField` fields populated with the quantity represented by the individual message we can ensure they're aggregated in the cache in a way that is lock free and conflict free.\n\nBe sure to check out `phonon.field.Fields` for more types you can aggregate!\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuzzfeed%2Fphonon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbuzzfeed%2Fphonon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbuzzfeed%2Fphonon/lists"}