{"id":49341909,"url":"https://github.com/nihiyama/ffq","last_synced_at":"2026-04-27T04:30:37.707Z","repository":{"id":254360343,"uuid":"846303189","full_name":"nihiyama/ffq","owner":"nihiyama","description":"File-based FIFO Queue","archived":false,"fork":false,"pushed_at":"2025-02-03T09:17:54.000Z","size":153,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-11T08:25:28.400Z","etag":null,"topics":["fast","fifo-queue","file-based","queue","simple"],"latest_commit_sha":null,"homepage":"","language":"Go","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/nihiyama.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-08-22T23:38:56.000Z","updated_at":"2025-07-08T04:19:26.000Z","dependencies_parsed_at":"2024-12-15T15:27:10.097Z","dependency_job_id":"7bae8528-d7b1-4569-a02b-dd12296457a4","html_url":"https://github.com/nihiyama/ffq","commit_stats":null,"previous_names":["nihiyama/ffq"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/nihiyama/ffq","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nihiyama%2Fffq","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nihiyama%2Fffq/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nihiyama%2Fffq/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nihiyama%2Fffq/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nihiyama","download_url":"https://codeload.github.com/nihiyama/ffq/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nihiyama%2Fffq/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32323211,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-26T23:26:28.701Z","status":"online","status_checked_at":"2026-04-27T02:00:06.769Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["fast","fifo-queue","file-based","queue","simple"],"created_at":"2026-04-27T04:30:35.465Z","updated_at":"2026-04-27T04:30:37.701Z","avatar_url":"https://github.com/nihiyama.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n    \u003cpicture\u003e\n        \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"./assets/logo-dark.drawio.svg\"\u003e\n        \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"./assets/logo-light.drawio.svg\"\u003e\n        \u003cimg alt=\"FFQ logo\" src=\"./assets/logo-dark.drawio.svg\" width=\"250\"\u003e\n    \u003c/picture\u003e\n\u003c/div\u003e\n\nFFQ (File-Based FIFO Queue) is a file-based system for managing FIFO queues. FFQ is developed using only the standard modules of Golang, without relying on any external modules or libraries. As a result, there is no need to manage dependencies, making it simple and lightweight. FFQ provides a simple and high-level API, making it easy to perform queue operations. With support for generics, you can enqueue data of any type into the queue. FFQ is designed for high performance , with speed primarily dependent on serialization and I/O during queue operations (almost lock-free, completely lock-free using SPSC). By default, FFQ uses json.Marshal and json.Unmarshal for serialization, but you can customize it by providing functions with compatible interfaces for serialization and deserialization. The queue file format assumes JSON arrays per line, so custom codecs must remain JSON-compatible; non-JSON formats are not supported.  \nSince FFQ stores the queue on files, even if the system goes down, you can resume reading from the queue without losing the progress of dequeued items. This implementation ensures reliability and data persistence, allowing seamless continuation from where you left off.\n\n[![](https://img.shields.io/github/actions/workflow/status/nihiyama/ffq/test.yaml?branch=main\u0026longCache=true\u0026label=Test\u0026logo=github%20actions\u0026logoColor=fff)](https://github.com/nihiyama/ffq/actions?query=workflow%3ATest)\n[![GoDoc](https://img.shields.io/badge/doc-reference-00ADD8.svg?logo=go)](https://pkg.go.dev/github.com/nihiyama/ffq)\n[![Go Report Card](https://goreportcard.com/badge/github.com/nihiyama/ffq)](https://goreportcard.com/report/github.com/nihiyama/ffq)\n[![Coverage Status](https://coveralls.io/repos/github/nihiyama/ffq/badge.svg?branch=main)](https://coveralls.io/github/nihiyama/ffq?branch=main)\n\n## Usage\n\nWe provide both SimpleQueue and GroupQueue. A GroupQueue is a collection of SimpleQueue instances, where each SimpleQueue is managed under a unique ID, allowing efficient management of multiple queues. For more information about each type of queue, please refer to the [Architecture section](#architecture). Choose the queue type that best suits your use case.\n\nFor detailed usage, you can refer to the [code examples](./examples/README.md) or check the documentation on [GoDoc](https://pkg.go.dev/github.com/nihiyama/ffq).\n\n\n### Simple Queue\n\nFor simplicity, the combination of Enqueue/Dequeue and BulkEnqueue/BulkDequeue is presented; however, feel free to　mix and match them to suit your use case.\n\n#### Enqueue/Dequeue\n\n```go\nfunc main() {\n    // Data is a struct with any field.\n    q, err := NewQueue[Data](\"example\")\n    if err != nil {\n        // catch serious error\n        panic(err)\n    }\n\n    var wg sync.WaitGroup\n\n    // startup dequeue goroutine\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        for {\n            // continue to dequeue repeatedly\n            m, err := q.Dequeue()\n            if err != nil {\n                if ffq.IsErrQueueClose(err) {\n                    // if qeueu is closed, close index and finish goroutine\n                    q.CloseIndex()\n                    return\n                }\n            }\n            q.UpdateIndex(m)\n        }\n    }(\u0026wg)\n\n    // Initialization is performed after starting the dequeue goroutine \n    // and before starting the enqueue goroutine.\n    // This ensures that data that has not yet been dequeued can be safely dequeued.\n    q.WaitInitialize()\n\n    // startup enqueue goroutine\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        // data has []*Data type.\n        data := makeData()\n\n        // enqueue\n        for _, d := range data {\n            q.Enqueue(d)\n        }\n\n        // finally, queueu is closed\n        q.CloseQueue()\n    }(\u0026wg)\n\n    wg.Wait()\n}\n```\n\n#### BulkEnqueue/BulkDequeue\n\n```go\nfunc main() {\n    // Data is a struct with any field.\n    q, err := NewQueue[Data](\"example\")\n    if err != nil {\n        // catch serious error\n        panic(err)\n    }\n\n    var wg sync.WaitGroup\n\n    // startup dequeue goroutine\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        for {\n            // continue to dequeue repeatedly\n            ms, err := q.BulkDequeue(size, lazy)\n            if err != nil {\n                if ffq.IsErrQueueClose(err) {\n                    // if qeueu is closed, close index and finish goroutine\n                    q.CloseIndex()\n                    return\n                }\n            }\n            if len(ms) \u003e 0 {\n                // update index\n                q.UpdateIndex(ms[len(ms)-1])\n            }\n        }\n    }(\u0026wg)\n\n    // Initialization is performed after starting the dequeue goroutine \n    // and before starting the enqueue goroutine.\n    // This ensures that data that has not yet been dequeued can be safely dequeued.\n    q.WaitInitialize()\n\n    // startup enqueue goroutine\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        // data has []*Data type.\n        data := makeData()\n\n        // enqueue\n        q.BulkEnqueue(data)\n\n        // finally, queueu is closed\n        q.CloseQueue()\n    }(\u0026wg)\n\n    wg.Wait()\n}\n```\n\n### Group Queue\n\nFor simplicity, the combination of Enqueue/Dequeue and BulkEnqueue/BulkDequeue, as with Simple Queue, is presented; however, feel free to mix and match them to suit your use case.\n\n#### Enqueue/Dequeue\n\n```go\nfunc main() {\n    // Data is a struct with any field.\n    gq, err := NewGroupQueue[Data](\"example\")\n    if err != nil {\n        // catch serious error\n        panic(err)\n    }\n\n    var wg sync.WaitGroup\n\n    // startup dequeue goroutine\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        for {\n            // continue to dequeue repeatedly\n            m, err := gq.Dequeue()\n            if err != nil {\n                if ffq.IsErrQueueClose(err) {\n                    // if qeueu is closed, close index and finish goroutine\n                    gq.CloseIndex()\n                    return\n                }\n            }\n            gq.UpdateIndex(m)\n        }\n    }(\u0026wg)\n\n    // Initialization is performed after starting the dequeue goroutine \n    // and before starting the enqueue goroutine.\n    // This ensures that data that has not yet been dequeued can be safely dequeued.\n    gq.WaitInitialize()\n\n    // startup enqueue goroutine 1.\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        // data has []*Data type.\n        data := makeData()\n\n        // enqueue\n        for _, d := range data {\n            gq.Enqueue(\"q1\", d)\n        }\n\n        // finally, queueu is closed\n        gq.CloseQueue()\n    }(\u0026wg)\n\n    // startup enqueue goroutine 2.\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        // data has []*Data type.\n        data := makeData()\n\n        // enqueue\n        for _, d := range data {\n            gq.Enqueue(\"q2\", d)\n        }\n\n        // finally, queueu is closed\n        gq.CloseQueue()\n    }(\u0026wg)\n\n    wg.Wait()\n}\n```\n\n#### BulkEnqueue/BulkDequeue\n\n```go\nfunc main() {\n    // Data is a struct with any field.\n    gq, err := NewGroupQueue[Data](\"example\")\n    if err != nil {\n        // catch serious error\n        panic(err)\n    }\n\n    var wg sync.WaitGroup\n\n    // startup dequeue goroutine\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        for {\n            // continue to dequeue repeatedly\n            ms, err := gq.BulkDequeue(size, lazy)\n            if err != nil {\n                if ffq.IsErrQueueClose(err) {\n                    // if qeueu is closed, close index and finish goroutine\n                    gq.CloseIndex()\n                    return\n                }\n            }\n            if len(ms) \u003e 0 {\n                // update index\n                for _, m := range ms {\n                    m.UpdateIndex(m)\n                }\n            }\n        }\n    }(\u0026wg)\n\n    // Initialization is performed after starting the dequeue goroutine \n    // and before starting the enqueue goroutine.\n    // This ensures that data that has not yet been dequeued can be safely dequeued.\n    gq.WaitInitialize()\n\n    // startup enqueue goroutine 1.\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        // data has []*Data type.\n        data := makeData()\n\n        // enqueue\n        gq.BulkEnqueue(\"q1\", data)\n\n        // finally, queueu is closed\n        gq.CloseQueue()\n    }(\u0026wg)\n\n    // startup enqueue goroutine 2.\n    wg.Add(1)\n    go func(wg *sync.WaitGroup) {\n        defer wg.Done()\n        // data has []*Data type.\n        data := makeData()\n\n        // enqueue\n        gq.BulkEnqueue(\"q2\", data)\n\n        // finally, queueu is closed\n        gq.CloseQueue()\n    }(\u0026wg)\n\n    wg.Wait()\n}\n```\n\n### Options\n\nWhen creating a Queue instance, you can set options.\nOptions include the following.\n\n| function name | type | default | detail |\n| --- | --- | --- | --- |\n| WithFileDir | string | `/tmp/ffq` | WithFileDir sets the directory where the queue files are stored. |\n| WithQueueSize | int | `100` | WithQueueSize sets the maximum number of items that can be held in the queue. |\n| WithMaxPages | int | `2` | WithMaxPages sets the number of files used in a single rotation cycle. |\n| WithEncoder | func(v any) ([]byte, error) | `json.Marshal` | WithEncoder sets a custom encoder function |\n| WithDecoder | func(data []byte, v any) error | `json.Unmarshal` | WithDecoder sets a custom decoder function. |\n| WithQueueType | ffq.QueueType | `ffq.SPSC` | WithQueueType can use `ffq.SPSC` or `ffq.MPSC`. It is possible to switch between Single Producer Single Consumer and Multiple Producer Single Consumer. |\n| WithGroupSize | int | `10` | WithGroupSize sets a GroupQueue size. It can only be used with GroupQueue. |\n\nWhen you create an instance using the NewQueue or NewGroupQueue function you can give options.\n\n```go\nfunc main() {\n    q, err := NewQueue[Data](\n        \"example\",\n        ffq.WithFileDir(\"/tmp\"),\n        ffq.WithQueueSize(100),\n        ...\n    )\n}\n```\n\n\u003e [!NOTE]  \n\u003e Once the options are set and running, do not change them. Doing so may cause data inconsistencies. If you wish to change an option, make sure that there are no outstanding queues, and while ffq is not running, delete the entire queue management directory before changing the option.\n\n### Additional Settings\n\nBefore creating an instance of Queue, you can perform the following configurations. Execute them as needed.\n\n| function name | type | default | detail |\n| --- | --- | --- | --- |\n| SetQueueBufferSize | int | 64kb | Buffer size used for writing to the Queue |\n| SetFSync | - | no fsync | Executes SetFSync to wait for the OS to complete writes |\n\n## Architecture\n\ncomming soon...\n\n## Benchmark\n\nA dataset with 12 keys was prepared, where each key has corresponding string, int, slice, and map values (more than 1kb). This dataset was used to conduct benchmark tests at four different scales: 10, 100 and 1000 data points.\n\n```\ngoos: linux\ngoarch: arm64\npkg: github.com/nihiyama/ffq/bench\nBenchmarkGoJSONSimpleQueueEnqueueDequeue/Size10-8                  10000            181210 ns/op           28741 B/op         44 allocs/op\nBenchmarkGoJSONSimpleQueueEnqueueDequeue/Size100-8                  1712            692693 ns/op          286619 B/op        407 allocs/op\nBenchmarkGoJSONSimpleQueueEnqueueDequeue/Size1000-8                  300           3857455 ns/op         2797539 B/op       4018 allocs/op\nBenchmarkGoJSONSimpleQueueBulkEnqueueDequeue/Size10-8              24903             49034 ns/op           29538 B/op         21 allocs/op\nBenchmarkGoJSONSimpleQueueBulkEnqueueDequeue/Size100-8              3540            296702 ns/op          455527 B/op        118 allocs/op\nBenchmarkGoJSONSimpleQueueBulkEnqueueDequeue/Size1000-8              454           2645481 ns/op         7374591 B/op       1068 allocs/op\nBenchmarkGoJSONSimpleQueueEnqueueDequeue_5MP/Size10-8               3736            530937 ns/op          144174 B/op        216 allocs/op\nBenchmarkGoJSONSimpleQueueEnqueueDequeue_5MP/Size100-8               421           2673111 ns/op         1442705 B/op       2036 allocs/op\nBenchmarkGoJSONSimpleQueueEnqueueDequeue_5MP/Size1000-8               45          23225262 ns/op        14019820 B/op      20127 allocs/op\nBenchmarkGoJSONSimpleQueueBulkEnqueueDequeue_5MP/Size10-8           5536            204298 ns/op          135926 B/op         81 allocs/op\nBenchmarkGoJSONSimpleQueueBulkEnqueueDequeue_5MP/Size100-8                   847           1387673 ns/op         1980260 B/op        573 allocs/op\nBenchmarkGoJSONSimpleQueueBulkEnqueueDequeue_5MP/Size1000-8                   78          15155019 ns/op        35761256 B/op       5355 allocs/op\nBenchmarkGoJSONGroupQueueEnqueueDequeue_5Group/Size10-8                     1976            708317 ns/op          207140 B/op        464 allocs/op\nBenchmarkGoJSONGroupQueueEnqueueDequeue_5Group/Size100-8                     627           1750355 ns/op         1600943 B/op       2322 allocs/op\nBenchmarkGoJSONGroupQueueEnqueueDequeue_5Group/Size1000-8                     98          11004677 ns/op        14102366 B/op      20367 allocs/op\nBenchmarkGoJSONGroupQueueBulkEnqueueDequeue_5Group/Size10-8                 3824            300221 ns/op          212297 B/op        326 allocs/op\nBenchmarkGoJSONGroupQueueBulkEnqueueDequeue_5Group/Size100-8                 829           1377020 ns/op         3243249 B/op        858 allocs/op\nBenchmarkGoJSONGroupQueueBulkEnqueueDequeue_5Group/Size1000-8                129           8533375 ns/op        35231912 B/op       5562 allocs/op\nBenchmarkJSONSimpleQueueEnqueueDequeue/Size10-8                            10000            231058 ns/op           40799 B/op        304 allocs/op\nBenchmarkJSONSimpleQueueEnqueueDequeue/Size100-8                            1443            861123 ns/op          405220 B/op       3007 allocs/op\nBenchmarkJSONSimpleQueueEnqueueDequeue/Size1000-8                            198           5934142 ns/op         3950594 B/op      30015 allocs/op\nBenchmarkJSONSimpleQueueBulkEnqueueDequeue/Size10-8                        17487             62894 ns/op           40425 B/op        281 allocs/op\nBenchmarkJSONSimpleQueueBulkEnqueueDequeue/Size100-8                        2642            431346 ns/op          488511 B/op       2715 allocs/op\nBenchmarkJSONSimpleQueueBulkEnqueueDequeue/Size1000-8                        294           3993813 ns/op         5721652 B/op      27056 allocs/op\nBenchmarkJSONSimpleQueueEnqueueDequeue_5MP/Size10-8                         2808            612809 ns/op          204116 B/op       1516 allocs/op\nBenchmarkJSONSimpleQueueEnqueueDequeue_5MP/Size100-8                         279           4034488 ns/op         2044779 B/op      15033 allocs/op\nBenchmarkJSONSimpleQueueEnqueueDequeue_5MP/Size1000-8                         32          32158689 ns/op        19854594 B/op     150107 allocs/op\nBenchmarkJSONSimpleQueueBulkEnqueueDequeue_5MP/Size10-8                     4473            268459 ns/op          193614 B/op       1381 allocs/op\nBenchmarkJSONSimpleQueueBulkEnqueueDequeue_5MP/Size100-8                     528           2246064 ns/op         2299095 B/op      13562 allocs/op\nBenchmarkJSONSimpleQueueBulkEnqueueDequeue_5MP/Size1000-8                     55          21459433 ns/op        27839735 B/op     135297 allocs/op\nBenchmarkJSONGroupQueueEnqueueDequeue_5Group/Size10-8                       1882            725399 ns/op          269376 B/op       1765 allocs/op\nBenchmarkJSONGroupQueueEnqueueDequeue_5Group/Size100-8                       525           2311979 ns/op         2185272 B/op      15303 allocs/op\nBenchmarkJSONGroupQueueEnqueueDequeue_5Group/Size1000-8                       86          14097208 ns/op        19934410 B/op     150354 allocs/op\nBenchmarkJSONGroupQueueBulkEnqueueDequeue_5Group/Size10-8                   3285            317469 ns/op          273905 B/op       1626 allocs/op\nBenchmarkJSONGroupQueueBulkEnqueueDequeue_5Group/Size100-8                   698           1626522 ns/op         3192447 B/op      13831 allocs/op\nBenchmarkJSONGroupQueueBulkEnqueueDequeue_5Group/Size1000-8                  111          10180737 ns/op        31272311 B/op     135521 allocs/op\nBenchmarkSonicJSONSimpleQueueEnqueueDequeue/Size10-8                       10000            182738 ns/op           33547 B/op         54 allocs/op\nBenchmarkSonicJSONSimpleQueueEnqueueDequeue/Size100-8                       1268            793526 ns/op          317641 B/op        506 allocs/op\nBenchmarkSonicJSONSimpleQueueEnqueueDequeue/Size1000-8                       249           4663699 ns/op         2883757 B/op       5012 allocs/op\nBenchmarkSonicJSONSimpleQueueBulkEnqueueDequeue/Size10-8                   21866             56680 ns/op           31869 B/op         22 allocs/op\nBenchmarkSonicJSONSimpleQueueBulkEnqueueDequeue/Size100-8                   3098            359794 ns/op          371931 B/op        114 allocs/op\nBenchmarkSonicJSONSimpleQueueBulkEnqueueDequeue/Size1000-8                   320           3644208 ns/op        11093796 B/op       1069 allocs/op\nBenchmarkSonicJSONSimpleQueueEnqueueDequeue_5MP/Size10-8                    3592            570777 ns/op          165500 B/op        265 allocs/op\nBenchmarkSonicJSONSimpleQueueEnqueueDequeue_5MP/Size100-8                    367           2962512 ns/op         1574216 B/op       2527 allocs/op\nBenchmarkSonicJSONSimpleQueueEnqueueDequeue_5MP/Size1000-8                    39          26188324 ns/op        14512105 B/op      25088 allocs/op\nBenchmarkSonicJSONSimpleQueueBulkEnqueueDequeue_5MP/Size10-8                5238            222071 ns/op          143110 B/op         85 allocs/op\nBenchmarkSonicJSONSimpleQueueBulkEnqueueDequeue_5MP/Size100-8                685           1665518 ns/op         1713373 B/op        562 allocs/op\nBenchmarkSonicJSONSimpleQueueBulkEnqueueDequeue_5MP/Size1000-8                54          21254885 ns/op        52341309 B/op       5385 allocs/op\nBenchmarkSonicJSONGroupQueueEnqueueDequeue_5Group/Size10-8                  1948            710172 ns/op          256895 B/op        514 allocs/op\nBenchmarkSonicJSONGroupQueueEnqueueDequeue_5Group/Size100-8                  620           1786605 ns/op         1770529 B/op       2783 allocs/op\nBenchmarkSonicJSONGroupQueueEnqueueDequeue_5Group/Size1000-8                  96          11790819 ns/op        14796516 B/op      25320 allocs/op\nBenchmarkSonicJSONGroupQueueBulkEnqueueDequeue_5Group/Size10-8              3591            313545 ns/op          251767 B/op        329 allocs/op\nBenchmarkSonicJSONGroupQueueBulkEnqueueDequeue_5Group/Size100-8              858           1307271 ns/op         2398778 B/op        817 allocs/op\nBenchmarkSonicJSONGroupQueueBulkEnqueueDequeue_5Group/Size1000-8             115          10232173 ns/op        56570411 B/op       5574 allocs/op\nPASS\nok      github.com/nihiyama/ffq/bench   177.265s\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnihiyama%2Fffq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnihiyama%2Fffq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnihiyama%2Fffq/lists"}