dsrees / javaphoenixclient Goto Github PK
View Code? Open in Web Editor NEWPhoenix client for the JVM built with Kotlin
License: MIT License
Phoenix client for the JVM built with Kotlin
License: MIT License
Hello. I have faced with the crash after the device was sleeping for a while.
Steps to reproduce:
1 - Start socket session in an app
2 - Switch a device to the sleep mode
3 - Exit from sleep mode after a while
E AndroidRuntime: at java.lang.Thread.run(Thread.java:764)
E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E AndroidRuntime: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E AndroidRuntime: at okhttp3.internal.connection.RealCall$AsyncCall.run(SourceFile:519)
E AndroidRuntime: at okhttp3.internal.ws.RealWebSocket$connect$1.onResponse(SourceFile:197)
E AndroidRuntime: at okhttp3.internal.ws.RealWebSocket.failWebSocket(SourceFile:592)
E AndroidRuntime: at org.phoenixframework.WebSocketTransport.onFailure(SourceFile:136)
E AndroidRuntime: at org.phoenixframework.Socket$connect$3.invoke(SourceFile:320)
E AndroidRuntime: at org.phoenixframework.Socket$connect$3.invoke(SourceFile:320)
E AndroidRuntime: at org.phoenixframework.Socket.onConnectionError$JavaPhoenixClient(SourceFile:603)
E AndroidRuntime: at org.phoenixframework.Socket.triggerChannelError(SourceFile:455)
E AndroidRuntime: at org.phoenixframework.Channel.trigger$JavaPhoenixClient$default(SourceFile:392)
E AndroidRuntime: at org.phoenixframework.Channel.trigger$JavaPhoenixClient(SourceFile:399)
E AndroidRuntime: at org.phoenixframework.Channel.trigger$JavaPhoenixClient(SourceFile:409)
E AndroidRuntime: at org.phoenixframework.Channel$10.invoke(SourceFile:206)
E AndroidRuntime: at org.phoenixframework.Channel$10.invoke(SourceFile:214)
E AndroidRuntime: at org.phoenixframework.Socket.removeFromSendBuffer$JavaPhoenixClient(SourceFile:471)
E AndroidRuntime: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object kotlin.Pair.getFirst()' on a null object reference
Device: Samsung S8+ (9.0)
Version: com.github.dsrees:JavaPhoenixClient: 1.2.0
I'm getting a lot of this on a recent library version. Could you look at this?
java.util.ConcurrentModificationException:
at java.util.ArrayList$Itr.next (ArrayList.java:860)
at org.phoenixframework.Socket.onConnectionError$JavaPhoenixClient (Socket.java:511)
at org.phoenixframework.Socket$connect$3.invoke (Socket.java:235)
at org.phoenixframework.Socket$connect$3.invoke (Socket.java:61)
at org.phoenixframework.WebSocketTransport.onFailure (WebSocketTransport.java:136)
at okhttp3.internal.ws.RealWebSocket.failWebSocket (RealWebSocket.java:570)
at okhttp3.internal.ws.RealWebSocket$1.onFailure (RealWebSocket.java:216)
at okhttp3.RealCall$AsyncCall.execute (RealCall.java:180)
at okhttp3.internal.NamedRunnable.run (NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:636)
at java.lang.Thread.run (Thread.java:784)
If the socket connection is lost due to a loss in network connectivity, the connection
needs to be reset. Example of this is to open a websocket and then switch to Airplane mode on Android. This will trigger an SSLException, killing the connection. However socket.isConnected
will still return true
until the heartbeat is not responded to.
javax.net.ssl.SSLException: Write error: ssl=0x744bbdcd08: I/O error during system call, Broken pipe
at com.android.org.conscrypt.NativeCrypto.SSL_write(Native Method)
at com.android.org.conscrypt.NativeSsl.write(NativeSsl.java:414)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket$SSLOutputStream.write(ConscryptFileDescriptorSocket.java:623)
at okio.Okio$1.write(Okio.java:79)
at okio.AsyncTimeout$1.write(AsyncTimeout.java:180)
at okio.RealBufferedSink.flush(RealBufferedSink.java:224)
at okhttp3.internal.ws.WebSocketWriter.writeControlFrame(WebSocketWriter.java:146)
at okhttp3.internal.ws.WebSocketWriter.writeClose(WebSocketWriter.java:106)
at okhttp3.internal.ws.RealWebSocket.writeOneFrame(RealWebSocket.java:507)
at okhttp3.internal.ws.RealWebSocket$1.run(RealWebSocket.java:159)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
In PhxPush.kt
/**
* Starts the Timer which will trigger a timeout after a specific delay
* in milliseconds is reached.
*/
fun startTimeout() {
this.timeoutTimer?.cancel()
val ref = this.channel.socket.makeRef()
this.ref = ref
val refEvent = this.channel.replyEventName(ref)
this.refEvent = refEvent
// If a response is received before the Timer triggers, cancel timer
// and match the received event to it's corresponding hook.
this.channel.on(refEvent) {
this.cancelRefEvent()
this.cancelTimeout()
this.receivedMessage = it
// Check if there is an event status available
val message = it
message.status?.let {
this.matchReceive(it, message)
}
}
// Start the timer. If the timer fires, then send a timeout event to the Push
this.timeoutTimer = Timer()
this.timeoutTimer?.schedule(timeout) {
trigger("timeout", HashMap())
}
}
I think what is happenign is that if the timeout actually happens then a Message like PhxMessage(ref=chan_reply_8, topic=, event=, payload={status=timeout}, joinRef=null)
is triggered. This is fine. However the bindings created with this.channel.on(refEvent)
are never removed.
If the connection is lost the library automatically tries to reconnect.
However, if one of the initial Socket
params was an access token and the token expired in the meantime it will nevertheless be reused for the reconnect attempt. This leads to the server not accepting the reconnect requests.
We need some way to take over the reconnect strategy in the library client. Either a callback where we can pass new parameters or a way to disable the reconnect and handle it ourselves.
seeing this that takes down the whole app, not sure when it happens
java.lang.ArrayIndexOutOfBoundsException: length=3; index=3
at org.phoenixframework.PhxSocket$reconnectAfterMs$1.invoke(PhxSocket.kt:42)
at org.phoenixframework.PhxSocket$reconnectAfterMs$1.invoke(PhxSocket.kt:26)
at org.phoenixframework.PhxTimer.scheduleTimeout(PhxTimer.kt:31)
at org.phoenixframework.PhxChannel$1.invoke(PhxChannel.kt:71)
at org.phoenixframework.PhxChannel$1.invoke(PhxChannel.kt:6)
at org.phoenixframework.PhxTimer$scheduleTimeout$$inlined$schedule$1.run(Timer.kt:150)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
I saw a crash lately with the following stack trace. Any idea if this is related to your lib or the way I interact with it? I've been using this one before and nothing like this happened.
Fatal Exception: java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at org.phoenixframework.PhxChannel.trigger(PhxChannel.kt:384)
at org.phoenixframework.PhxSocket.triggerChannelError(PhxSocket.kt:381)
at org.phoenixframework.PhxSocket.remove(PhxSocket.kt:354)
at org.phoenixframework.PhxSocket.remove(PhxSocket.kt:437)
at okhttp3.internal.ws.RealWebSocket.failWebSocket(RealWebSocket.java:570)
at okhttp3.internal.ws.RealWebSocket$2.onFailure(RealWebSocket.java:220)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:161)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
This library seems very useful. However, the documentation is pretty minimal which makes it hard to get up and running quickly. I'm a beginner/intermediate Android dev and intermediate/advanced Elixir dev and I still haven't figured out how to connect successfully #29.
I may be doing something plainly wrong, but the docs aren't helping me much. I'd be happy to make a PR with more detailed documentation for getting started if others agree. @dsrees
At first thank you for your work and this nice library! :-)
I have some trouble with reconnections. While my research I found the following issue on phoenix's JS client.
I get the same behavior on this client.
If I call disconnect
and connect
again to simulate a connection drop, I can not push messages anymore. I still get error with unmatched topic
.
Message(joinRef=null, ref=16, topic=room:lobby, event=chan_reply_16, rawPayload={response={reason=unmatched topic}, status=error})
Debugging the client show all things are connected
canPush = true
isJoined = true
socket.isConnected = true
I have looked at the linked issue and the merge requests. But I don't understand the cause or the solution to fix this by myself.
In case this is really a bug and someone can help me to understand the cause and have some ideas how to fix this, I want to create a PR for this.
looks like there is a bug in off
method of Channel
public fun off(event: String, ref: Int? = null) {
// Remove any subscriptions that match the given event and ref ID. If no ref
// ID is given, then remove all subscriptions for an event.
this.bindings = bindings
.filter { it.first == event && (ref == null || ref == it.second) }
.toMutableList()
}
If I see this correctly, this removed everything from list that doenst match and not remove the one item :)
This prevents me from seeing any messages.
Maybe I am doing sth wrong but that is what debugging showed me :)
Thanks for the library.
I'm having issues connecting and I haven't been able to track down the cause.
INTERNET
and ACCESS_NETWORK_STATE
permissions have been added to AndroidManifest.xml
.Here's my activity:
package com.mydomain.myapp
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import org.phoenixframework.PhxSocket
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity";
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
this.connectToChatRoom()
}
fun connectToChatRoom() {
// Create the Socket
val params = hashMapOf("token" to "abc123")
val url = "http://localhost:4000/socket/websocket"
val socket = PhxSocket(url, params)
// Listen to events on the Socket
socket.logger = { Log.d("TAG", it) }
socket.onOpen { Log.d("TAG", "Socket Opened") }
socket.onClose { Log.d("TAG", "Socket Closed") }
socket.onError { throwable, response ->
throwable?.printStackTrace()
Log.d("Message", throwable?.message)
Log.d("Response:", "${response?.toString()}")
Log.d(throwable.toString(), "\"Socket Error\"")
}
socket.connect()
// Join channels and listen to events
val chatroom = socket.channel("user:1")
chatroom.on("new_message") {
// `it` is a PhxMessage object
val payload = it.payload
Log.d("TAG", "payload received")
}
chatroom.join()
.receive("ok") { /* Joined the chatroom */ }
.receive("error") { /* failed to join the chatroom */ }
}
}
And here's my log:
2018-12-14 13:24:30.806 17467-17467/com.mydomain.myapp D/NetworkSecurityConfig: No Network Security Config specified, using platform default
2018-12-14 13:24:30.857 17467-17484/com.mydomain.myapp D/TAG: Transport: error
2018-12-14 13:24:30.859 17467-17484/com.mydomain.myapp W/System.err: java.net.ConnectException: Failed to connect to localhost/127.0.0.1:4000
2018-12-14 13:24:30.859 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:242)
2018-12-14 13:24:30.859 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.connection.RealConnection.connect(RealConnection.java:160)
2018-12-14 13:24:30.859 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:257)
2018-12-14 13:24:30.859 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:135)
2018-12-14 13:24:30.859 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.connection.StreamAllocation.newStream(StreamAllocation.java:114)
2018-12-14 13:24:30.859 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.RealCall$AsyncCall.execute(RealCall.java:147)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
2018-12-14 13:24:30.860 17467-17484/com.mydomain.myapp W/System.err: at java.lang.Thread.run(Thread.java:761)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: Caused by: java.net.ConnectException: Connection refused
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: at java.net.PlainSocketImpl.socketConnect(Native Method)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:334)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:196)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:178)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:356)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: at java.net.Socket.connect(Socket.java:605)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.platform.AndroidPlatform.connectSocket(AndroidPlatform.java:71)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: at okhttp3.internal.connection.RealConnection.connectSocket(RealConnection.java:240)
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp W/System.err: ... 21 more
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp D/message: Failed to connect to localhost/127.0.0.1:4000
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp D/java.net.ConnectException: Failed to connect to localhost/127.0.0.1:4000: "Socket Error"
2018-12-14 13:24:30.861 17467-17484/com.mydomain.myapp D/Response:: null
Any suggestions are appreciated!
https://blog.gradle.org/jcenter-shutdown
I stumbled across this today when I was unable to fetch this dependency. Do you have plans to publish somewhere else?
Hi, it's been a long time since the last release. Could you please release a new version?
The library in the current state will not work when using proguard.
PhxMessage
class member names are used to parse the response from WS.
The solution would be to add @SerializeName
annotation, this way there is no need to add any additional proguard rules (apart from the ones for gson and okhhtp).
As for now you have to specify a rule like this
-keepclassmembernames class org.phoenixframework.PhxMessage { *; }
Because Gson doesn't respect default values of parsed classes, if the payload
is missing in the received event JSON then its value will still be null, breaking the non-nullability contract for the field (it is defined as val payload: Payload = Hashmap()
in the Message
class).
A quick fix would be to make the Payload
field nullable.
Also, is there a reason why Message
isn't a data class?
I am facing an issue after updating to the latest AGP v8 that after obfuscation (release build) I keep receiving phx_error
even though the proxy confirms that I got okay from the server.
Any comments or thoughts about this issue?
I tried both 1.0.0 and 1.0.1 versions.
Hello! i have this error on all devices with api<24.
java.lang.NoClassDefFoundError: org.phoenixframework.PhxSocket$1$1
at org.phoenixframework.PhxSocket.<init>(PhxSocket.kt:123)
it's impossible to use your lib with this problem. I saw you commited solution for this problem, but it's not released. Is it working? will you release it? when?
release the initial version to bintray via a travis build.
The last PR introduced a bug where the lib tries to reconnect even when the websocket is closed intentionally by calling disconnect()
This is what is happening:
disconnect()
is calledonConnectionClosed()
is invokedreconnectTimer
is scheduledreconnectTimer
connects to WebSocket againI think we should somehow distinguish disconnect()
called be the user and by the library itself. This would give us an option to know wether we should still want to try to reconnect or not.
@dsrees Could you look at this?
Will the error callback on PhxSocket be called when sending heartbeat fails?
From what I've seen it does not, but what is the purpose of the heartbeat then?
The library in the current state will not work when using proguard.
PhxMessage
class member names are used to parse the response from WS.
The solution would be to add @SerializeName
annotation, this way there is no need to add any additional proguard rules (apart from the ones for gson and okhhtp).
As for now you have to specify a rule like this
-keepclassmembernames class org.phoenixframework.PhxMessage { *; }
When serializing Payload objects, the default JSON behaviour is to convert from camel case to snake case: https://github.com/dsrees/JavaPhoenixClient/blob/master/src/main/kotlin/org/phoenixframework/Defaults.kt#L52
I presume it was done deliberately for internal reasons, but it is a bit of a surprise.
I don't think this is what the equivalent Javascript library does: https://github.com/phoenixframework/phoenix/blob/master/assets/js/phoenix.js#L648
Is this the best way to extract data from the Message.payload or am I missing a trick?
private fun onPhoenixOpen(m : Message) {
val response = m.payload["response"] as LinkedTreeMap<*, *>
val permissionsTokenEncoded = response.get("perms_token")
}
LinkedTreeMap is an implementation detail that's leaking out of JavaPhoenixClient and I would rather avoid it, especially if you plan to switch to the built-in serialization library in future.
When leaving a channel I receive immediately the events:
Receive: {"event":"phx_reply","payload":{"response":{},"status":"ok"},"ref":"10","topic":"my_topic"}
Receive: {"event":"phx_close","payload":{},"ref":"7","topic":"my_topic"}
However, channel.onClose() is triggered 10 seconds later due to timeout. This happens everytime.
Sometimes you might want to check responseCode or sth when your WS connection fails.
Maybe it would be worth considering returning sth different than just Throwable?
Expose the OkHttp client to be configurable while creating the PhxSocket
. See the issue #69 on the JavaPhoenixChannels repo
Received this crash log. Only one instance of it so far, have not done any digging into what could have caused it. Reporting here for a reference
Fatal Exception: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object kotlin.Triple.getFirst()' on a null object reference
at org.phoenixframework.PhxChannel.trigger(PhxChannel.kt:337)
at org.phoenixframework.PhxPush.trigger(PhxPush.kt:191)
at org.phoenixframework.PhxPush$startTimeout$$inlined$schedule$1.run(Timer.kt:149)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Ideally, the User of this client should be able to use any JSON library of their choosing. Initial thought is to create a JsonConverter
interface that accepts raw JSON string and has it pass back the decoded object that we need. This would also require a Builder
of some sort to construct the PhxSocket
class with the JsonConverter
Any ideas are welcome on this.
OkHttp terminated support for earlier android versions in 3.13. THis client should not prevent android min target because of a dependency. Retrofit is also pinned to 3.12.2 so this is a safe downgrade
Hi @dsrees
I wanted to update the library but I see that a lot has changed.
Could you provide a bit more information about reconnection strategy?
The reason I'm asking this is that I do have my own reconnection strategy for WS errors and know it would be duplicated with the one provided from the library.
I do see that you do retry only for specific errors and I'm wondering if it would be possible to maybe implement this is a bit more configurable way? So we could choose the strategy like only for errors or when the WS was closed or both. Does it make sense?
Just to stay up to date
Hi! When can we expect the release of version 1.1.3 to maven repository? The latest one is still 1.1.2 and there's a fix on 1.1.3 which I would be interested in
For every channel push a new timer (and thus a new thread) is created. This is quite expensive compared to using a ScheduledThreadPoolExecutor which would be re-using threads.
I plan on trying to convert all usages of Timers to using a shared ScheduledThreadPoolExecutor later in the week if this seems like a good change.
After upgrading from 0.1.8 to the latest version (0.2.5) we are noticing that the Heardbeats are not sent regularly anymore. Instead they seem to be sent only once after the connexion is established.
After looking quickly at the code it seems that the hearbeat scheduling is done in Socket
, line 370:
dispatchQueue.queue(heartbeatInterval, TimeUnit.MILLISECONDS) { sendHeartbeat() }
And looking at the implementation (dispatchQueue
is a ScheduledDispatchQueue
), I see that it's based on ScheduledThreadPoolExecutor.schedule
which is a one-shot API, not a periodic one.
Is this correct?
Received this a couple of times. client version 0.2.5
Fatal Exception: java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.next(ArrayList.java:860)
at org.phoenixframework.Socket.triggerChannelError(Socket.kt:467)
at org.phoenixframework.Socket.onConnectionError$JavaPhoenixClient(Socket.kt:458)
at org.phoenixframework.Socket$connect$3.invoke(Socket.kt:229)
at org.phoenixframework.Socket$connect$3.invoke(Socket.kt:66)
at org.phoenixframework.WebSocketTransport.onFailure(Transport.kt:134)
at okhttp3.internal.ws.RealWebSocket.failWebSocket(RealWebSocket.java:571)
at okhttp3.internal.ws.RealWebSocket$1.onFailure(RealWebSocket.java:221)
at okhttp3.RealCall$AsyncCall.execute(RealCall.java:225)
at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
JS version goes up to 10 seconds https://github.com/phoenixframework/phoenix/blob/master/assets/js/phoenix.js#L729,
here we go up to 100 seconds https://github.com/dsrees/JavaPhoenixClient/blob/master/src/main/kotlin/org/phoenixframework/PhxSocket.kt#L49.
Is that on purpose or a simple typo?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.