reswifq / redis-client-vapor

Adapter to use vapor/redis with reswifq.
GNU Lesser General Public License v3.0
1 stars 1 forks source link

Swift Package Manager Hangs w/ Vapor 3 #4

Open ozitrance opened 6 years ago

ozitrance commented 6 years ago

Hey There

I'm trying to add this to my vapor 3 project but I just can't make it work no matter what I try.

SPM keeps hanging and doesn't provide too much info. A lot of trial and error made me believe this is happening because this package is trying to download some vapor 2 packages that conflict with Vapor3 that's already there..

I tried removing the dependencies from your package and add Redis manually (RedisClient is downloaded w/ Reswifq right?) but I guess there's something there that VaporRedisClient needs? Like the 'sockets' package? VaporRedisClient.swift complains about RedisClient too if I do it this way.. Also tried to just copy VaporRedisClient.swift (without SPM) and then adding 'sockets' and 'tls' w/ SPM and manually but I just end up w/ more errors.

Here's my Package.swift file:

// swift-tools-version:4.0
import PackageDescription

let package = Package(
    name: "ABot1",
    dependencies: [
        // 💧 A server-side Swift web framework.
        .package(url: "https://github.com/vapor/vapor.git", .upToNextMajor(from: "3.0.0-rc")),
        .package(url: "https://github.com/vapor/mysql-driver.git", .upToNextMajor(from: "3.0.0-rc")),
        .package(url: "https://github.com/tid-kijyun/Kanna.git", .upToNextMajor(from: "4.0.0")),
        .package(url: "https://github.com/SwiftyBeaver/SwiftyBeaver.git", .upToNextMajor(from: "1.0.0")),
        .package(url: "https://github.com/vapor/redis.git", .upToNextMajor(from: "3.0.0-rc")),
        .package(url: "https://github.com/reswifq/reswifq.git", .upToNextMajor(from: "1.3.0")),
        .package(url: "https://github.com/reswifq/redis-client-vapor.git", .upToNextMajor(from: "1.2.0")),

        ],
    targets: [
        .target(
            name: "App",
            dependencies: ["Vapor", "FluentMySQL", "Kanna", "SwiftyBeaver", "Redis", "Reswifq",  "VaporRedisClient"]
        ),
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App"]),
        ]
)

Any ideas? I really hope this can be solved, I really wanna try use Reswifq w/ Vapor...

Thanks!

valeriomazzeo commented 6 years ago

This package hasn't been updated to Vapor 3 yet.

You can either:

I suggest you try and create your own client using Vapor 3 dependencies already existing in your project. All you have to do is to conform to RedisClient.

ozitrance commented 6 years ago

Thank you for the quick response!

Yea I realized later it is not vapor 3 ready yet. I was able to connect to redis using the vapor/redis repository but not with reswifq.

Do you know if reswifq is ready for vapor 3? It seems like it was last updated before that release. I might be wrong, I tried so many combinations and I don’t remember exactly, but I think there’s a conflict in there, with the RedisClient reswifq is using and another one in vapor/redis 3 release. They say it’s still in beta and the documentation is definitely missing a lot.

I just want to know if I can use reswifq with vapor at all or the whole thing is not ready for vapor 3 yet.

Thanks again 🙏

valeriomazzeo commented 6 years ago

Reswifq is completely independent from Vapor or Kitura.

All you need in order to use Reswifq is a concrete implementation of a RedisClient. Whether that uses Vapor, Foundation, or Kitura it doesn't matter.

As I have already mentioned:

I suggest you try and create your own client using Vapor 3 dependencies already existing in your project. All you have to do is to conform to RedisClient.

Add https://github.com/vapor/redis to your dependencies, make Redis.RedisClient conform to RedisClient.RedisClient and you are good to go.

You don't need to import this repository to use Reswifq.

ozitrance commented 6 years ago

I’m gonna give it another try tonight.

Thank you!

ozitrance commented 6 years ago

I'm trying to implement this based on your version of the file but I'm having a problem with the execute function and I was hoping you can maybe guide me in the right direction with the issue I have.

In Vapor3 RedisClient is returning Future<RedisData> (Instead of Data like in Vapor 2 or RedisData for that matter). That means I need to map it and get the actual result inside a closure. Swift won't compile unless I provide another return value outside the closure and that eventually causes the function to return 2 RedisClientResponse objects when the first one is always the empty one I was "forced" to add. No matter what I tried I couldn't work around this...

It might be something simple, I'm not very experienced and Vapor is hard! I just really like the idea of Reswifq and threading with Swift. I'm hoping it's something simple...

I added my version of the execute function and a link to my version of VaporRedisClient below. I would love to hear your comments.

The code:

public func execute(_ command: String, arguments: [String]?) throws -> RedisClientResponse {
        var args = [RedisData]()

        if let arguments = arguments {
            for argument in arguments {
                args.append(RedisData(stringLiteral: argument))
            }
        }

        let response = self.client.command(command, args)

        let _ = response.map(to: RedisClientResponse.self) {
            result in

            return RedisClientResponse(response: result)
        }

        /// THE RETURN THAT ALWAYS EXECUTES EARLY BEFORE THE 'FUTURE' RETURNS..
        return RedisClientResponse(response: nil)
    }

And the link: https://github.com/ozitrance/redis-client-vapor/blob/master/Sources/VaporRedisClient/VaporRedisClient.swift

Thank you!

valeriomazzeo commented 6 years ago

The Reswifq API is synchronous (as it was Vapor 2). Vapor 3 and the new RedisClient have asynchronous APIs.

You can use a DispatchSemaphore in order to block the Reswifq RedisClient thread until you get a response from Vapor RedisClient then return.

Something like this:

let semaphore = DispatchSemaphore(value: 0)

var _result: WhateverTypeThatIs?

self.client.command(command, args).map(to: RedisClientResponse.self) { result in
  _result = result
  semaphore.signal()
}

semaphore.wait()

// Process result
// return response
ozitrance commented 6 years ago

Thanks for the quick response! Unfortunately I still can't make it work.

It seems like it blocks the same thread where the async work and signal to continue are.. So it's just waits forever. I tried using DispatchQueue to change threads but it's all the same... I might be wrong but I think the work inside the closure is always done on the blocked thread?

valeriomazzeo commented 6 years ago

I didn't look into the new Vapor/Redis so I can't tell on which queue the client sends its commands.

You can dispatch the client command using DispatchQueue.global().async, not sure it's a good solution long term, but at least you should be able to tell if it works.

ozitrance commented 6 years ago

Yea that’s what I tried but it doesn’t seem to apply to the code inside the Future closure. It still just waits.

Thank you so much for trying to help though.

Are there any plans to update Reswifq to support Vapor 3?