Closed crarau closed 6 years ago
Xcode doesn't run on Linux… can you be more specific about your problem?
@mxcl I've created this repository to demonstrate the issue: https://github.com/crarau/promise-kit-issue
What I've meant is that I'd like to use PromiseKit using swift server side. For this I've create a project that is deployed on Ubuntu 16.04. While testing on XCode I noticed that PromiseKit doesn't work the same in this project when compared to an iOS one.
OK, the problem is yours I am afraid, promises are asynchronous, so they need a runloop to work.
Something like:
promise.then {
NSRunloop.main.stop()
}
NSRunloop.main.run()
print("Done!")
Should make the project work, but really you want some kind of event-system on your server side code. To my knowledge, all of them provide one.
I'd love to get more info / guidance on this. I understand that a runloop is required, but wasn't aware that one wasn't available when running a server side swift project?
Promises are such an integral part of my workflow that imagining the nested closure mess i would get into without them makes me want to solve this.
I'm currently using the latest version of Kitura. I didn't quite get your example above. Would there be any way to get this to work?
to reproduce the issue I've created this repository: https://github.com/crarau/SwiftKit-ServerSide-Issue
import Foundation
import Kitura
import PromiseKit
class PromiseKitServerSide {
func test(completion:@escaping (String)->()) {
print("in test")
firstly {
return Promise.init(value: "promise")
}.then { value in
print("in then")
completion(value)
}.always {
completion("done!");
}
}
}
let router = Router()
router.get("/") { request, response, next in
PromiseKitServerSide().test(completion: { (result) in
response.send(result)
})
RunLoop.main.run()
}
print("starting server")
Kitura.addHTTPServer(onPort: 8888, with: router)
Kitura.run()
going in the browser and accessing http://127.0.0.1:8888/ in the console we see:
starting server
in test
the code doesn't get into then
or finally
.
Adding RunLoop.main.run()
doesn't change and RunLoop.main.stop()
doesn't exist.
Please advise,
Regards
Strictly we don't need a run loop. But the app has to enter some kind of wait state so it doesn't exit while the async stuff happens.
Also the GCD internals must be running. I don't really know what that requires.
Kitura blocks DispatchQueue.main, which is the default queue for then(). You will need to explicitly pass DispatchQueue.global to then, always, etc. As in:
firstly {
return Promise.init(value: "promise")
}.then (on:DispatchQueue.global()) { value in
print("in then")
completion(value)
}.always(on:DispatchQueue.global()) {
completion("done!");
}
Kitura blocks DispatchQueue.main
Wow. That seems crazy.
You can set the default queue that PromiseKit uses: https://github.com/mxcl/PromiseKit/blob/master/Sources/DispatchQueue%2BPromise.swift#L37-L52
I don't do any server side Swift. You, the people who do, are going to have tell me how to clarify the documentation.
You can set the default queue that PromiseKit uses: https://github.com/mxcl/PromiseKit/blob/master/Sources/DispatchQueue%2BPromise.swift#L37-L52
How we can set it?
func __PMKDefaultDispatchQueue() -> DispatchQueue {
return DispatchQueue.main
}
func __PMKSetDefaultDispatchQueue(_: DispatchQueue)
{}
Oh indeed, those are not implemented for SwiftPM. My bad. PR shouldn't be too hard though.
With PMK5, you can now do:
conf.Q = (map: DispatchQueue.global(), return: DispatchQueue.global())
Here's a quick example using Kitura:
import Foundation
import Kitura
import PromiseKit
import HeliumLogger
import LoggerAPI
HeliumLogger.use(.info)
conf.Q = (map: DispatchQueue.global(), return: DispatchQueue.global())
let router = Router()
router.get("/") { _, response, next in
Log.info("Request received")
after(seconds: 1.0).done {
Log.info("Sending response")
response.send("OK")
next()
}
}
Log.info("Starting server")
Kitura.addHTTPServer(onPort: 8888, with: router)
Kitura.run()
This produces output like:
[2017-11-29T21:20:04.206-08:00] [INFO] [main.swift:21 promisekitura] Starting server
[2017-11-29T21:20:04.213-08:00] [INFO] [HTTPServer.swift:124 listen(on:)] Listening on port 8888
[2017-11-29T21:20:11.491-08:00] [INFO] [main.swift:13 promisekitura] Request received
[2017-11-29T21:20:12.589-08:00] [INFO] [main.swift:15 promisekitura] Sending response
You can see that roughly a second elapses between the request being received and the response being sent, so the promise chain is working, and Kitura does send the response as expected:
~
❯ http http://localhost:8888
HTTP/1.1 200 OK
Connection: Keep-Alive
Content-Length: 2
Date: Thu, 30 Nov 2017 05:23:39 GMT
Keep-Alive: timeout=60
OK
Hope this helps!
Fixed in 5/6.
Running this in iOS the code is getting to
self.second...
but while running the same code on XCode on a server side project we never pass theself.first...