Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rudimentary q table #42

Merged
merged 1 commit into from
Jan 13, 2019
Merged

Rudimentary q table #42

merged 1 commit into from
Jan 13, 2019

Conversation

MattSkala
Copy link
Collaborator

@MattSkala MattSkala commented Dec 3, 2018

No description provided.

@rpytel1 rpytel1 force-pushed the rudimentary_qTable branch from d74284c to 1b6f50d Compare December 4, 2018 17:22
self.providers_offers = data['providers_offers']
self.self_state = data['self_state']

def choose_best_option(self, providers):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems very "hard coded"

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved values to the single constant to have less "hard coded code"

@rpytel1
Copy link
Collaborator

rpytel1 commented Dec 11, 2018

@Jaapp- I think smth failed here with Jenkins(or integration to git), because I think all the tests pass now and so it looks on the Jenkins.
@andrebreis @MattSkala @BloodyFool feel free to comment the code and I can repair it before merging.

@@ -34,21 +35,28 @@ def setup(args):
agent. All necessary configuration files are created and IRC communication is started.
:param args: If running in Testnet mode.
"""
global dna, config
global dna, qtable, config
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove dna

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -13,6 +13,8 @@
import subprocess
import shutil

from plebnet.agent.qtable import QTable

from plebnet.agent.dna import DNA
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove unused imports

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -218,6 +221,8 @@ def attempt_purchase():
"""
Check if enough money to buy a server, and if so, do so,
"""
config = PlebNetConfig()
qtable = QTable()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if it is crucial

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

removed

"""
Creates the QTable configuration for the child agent. This is done by copying the own QTable configuration and including the new host provider, the parent name and the transaction hash.
:param provider: the name the child tree name.
:param tree: tree of inheritance
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove line above

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -29,7 +29,9 @@ export DEBIAN_FRONTEND=noninteractive
cd

CHILD_DNA_FILE=~/.config/Child_DNA.json
#CHILD_QTABLE_FILE=
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HusainKapadia why is this commented?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed properly

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because when I wrote this the QTable.json had not been created. I'll add the correct paths if you haven't done so yet

@@ -228,65 +227,65 @@ def test_update_offer(self):
cloudomate_controller.update_offer = self.uo
PlebNetConfig.save = self.save

def test_attempt_purchase(self):
def test_attempt_purchase(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HusainKapadia I think it is better not to comment code but to remove it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@devos50
Copy link
Collaborator

devos50 commented Dec 14, 2018

It seems that the Plebnet job on Jenkins is filling up slots on our machines (because it is stuck): https://jenkins-ci.tribler.org. Please have a look at this 👍

@MattSkala
Copy link
Collaborator Author

MattSkala commented Dec 14, 2018

  1. It would be nice to mock cloudomate calls in tests so we have true unit tests. Right now the tests for QTable would break if any of cloudomate providers breaks, which probably should not be the case.

  2. Check what happens when a provider in cloudomate breaks (e.g. get_options raises an exception, purchase fails). The bot should be resilient and handle such cases by decreasing a reward and trying a different provider.

  3. Check if the calculate_measure is working correctly for unmetered bandwidth (e.g. linevast) and write a test case for that.

  4. I don't like how dictionary is used everywhere so the code is not type-safe (very JavaScript-ish :D). It would be better to use custom types or named tuples for provider offers and state.

  5. How are we going to handle VPN selection? Currently it's hardcoded to always use AzireVPN. It makes sense to use the cheapest VPN which is working for the selected VPS provider. It would be interesting if the bot can also learn which VPS providers do not care about traffic so we can save on VPN, and for which the VPN is a necessity for survival. Is it possible to integrate it somehow with the current QTable/should we create a separate QTable for VPN selection?

@MattSkala
Copy link
Collaborator Author

@devos50 @Jaapp- It looks like https://jenkins-ci.tribler.org/job/GH_Plebnet_PR_Tests/job/GH_PlebNet_coverage_check/17/console is stuck and all subsequent coverage check jobs are waiting for it to finish. Is it possible to kill the build now and set a timeout so it does not happen in future?

@devos50
Copy link
Collaborator

devos50 commented Dec 14, 2018

@MattSkala yes. @Jaapp- has login credentials for Jenkins so he can kill these jobs. In the job settings, you can specify either a fixed timeout or a dynamic timeout (that is based on the duration of previous runs).

@rpytel1
Copy link
Collaborator

rpytel1 commented Dec 16, 2018

@MattSkala I will try to do the 1-4 of your remarks now as I agree with them. Ad 5 I am not sure it is not better to do as seperate PR in the next sprint :)

  1. It would be nice to mock cloudomate calls in tests so we have true unit tests. Right now the tests for QTable would break if any of cloudomate providers breaks, which probably should not be the case.
  2. Check what happens when a provider in cloudomate breaks (e.g. get_options raises an exception, purchase fails). The bot should be resilient and handle such cases by decreasing a reward and trying a different provider.
  3. Check if the calculate_measure is working correctly for unmetered bandwidth (e.g. linevast) and write a test case for that.
  4. I don't like how dictionary is used everywhere so the code is not type-safe (very JavaScript-ish :D). It would be better to use custom types or named tuples for provider offers and state.
  5. How are we going to handle VPN selection? Currently it's hardcoded to always use AzireVPN. It makes sense to use the cheapest VPN which is working for the selected VPS provider. It would be interesting if the bot can also learn which VPS providers do not care about traffic so we can save on VPN, and for which the VPN is a necessity for survival. Is it possible to integrate it somehow with the current QTable/should we create a separate QTable for VPN selection?

@HusainKapadia
Copy link
Collaborator

@MattSkala I will try to do the 1-4 of your remarks now as I agree with them. Ad 5 I am not sure it is not better to do as seperate PR in the next sprint :)

  1. It would be nice to mock cloudomate calls in tests so we have true unit tests. Right now the tests for QTable would break if any of cloudomate providers breaks, which probably should not be the case.
  2. Check what happens when a provider in cloudomate breaks (e.g. get_options raises an exception, purchase fails). The bot should be resilient and handle such cases by decreasing a reward and trying a different provider.
  3. Check if the calculate_measure is working correctly for unmetered bandwidth (e.g. linevast) and write a test case for that.
  4. I don't like how dictionary is used everywhere so the code is not type-safe (very JavaScript-ish :D). It would be better to use custom types or named tuples for provider offers and state.
  5. How are we going to handle VPN selection? Currently it's hardcoded to always use AzireVPN. It makes sense to use the cheapest VPN which is working for the selected VPS provider. It would be interesting if the bot can also learn which VPS providers do not care about traffic so we can save on VPN, and for which the VPN is a necessity for survival. Is it possible to integrate it somehow with the current QTable/should we create a separate QTable for VPN selection?

@rpytel1 would you like to split the work? We can discuss about it tomorrow after or before the meeting.

@rpytel1
Copy link
Collaborator

rpytel1 commented Dec 16, 2018

@HusainKapadia no, I prefer to do it alone and finish it today.

@MattSkala
Copy link
Collaborator Author

I created a separate issue for the VPN selection: #49

Also, please rebase to the current develop and try to investigate why tests are failing on the CI: https://jenkins-ci.tribler.org/job/GH_Plebnet_PR_Tests/job/GH_PlebNet_tests/21/console

@rpytel1
Copy link
Collaborator

rpytel1 commented Dec 16, 2018

I think I did changes matching the remarks of @MattSkala. I did also rebase and resolved conflicts with develop.
There is one think I am currently unsure of: if we create child configuration, it comes with variable provider . Before in DNA there was only an info about the provider, without info about specific offer.
@HusainKapadia if you want you can check it now and make fix. I need to spend some time on other matters, but will probably check it during a night.

I don't know why two tests are crashing on Jenkins :(

@MattSkala
Copy link
Collaborator Author

Tests are failing because you are replacing cloudomate_controller module functions by a mock, so it influences other tests using those functions as well. Take a look at unittest.mock.patch ;)

@rpytel1 rpytel1 force-pushed the rudimentary_qTable branch 2 times, most recently from c0b9f4d to fb89e76 Compare December 31, 2018 18:16
@rpytel1
Copy link
Collaborator

rpytel1 commented Dec 31, 2018

PR is working with test fixed still in 2018 :D
Feel free to review it last time before merge :)
If all will be great, let me know and then I will make all this 11 commits into one :)

@MattSkala
Copy link
Collaborator Author

  1. Note that pickle does not serialize to JSON, but to a custom binary format. So the json_file variable name and the file name itself are misleading. For JSON serialization you would need to use the jsonpickle library instead. If you ask me, I'd prefer using JSON for easier debugging.

  2. When running plebnet check, I get the following error:

File "/usr/local/lib/python2.7/dist-packages/plebnet/cmdline.py", line 41, in execute
    args.func()
  File "/usr/local/lib/python2.7/dist-packages/plebnet/cmdline.py", line 66, in execute_check
    agent.check()
  File "/usr/local/lib/python2.7/dist-packages/plebnet/agent/core.py", line 113, in check
    select_provider()
  File "/usr/local/lib/python2.7/dist-packages/plebnet/agent/core.py", line 318, in select_provider
    if providers >= 1 and sum(providers.values()) > 0:
TypeError: unsupported operand type(s) for +: 'int' and 'ABCMeta'
  1. Please resolve the merge conflict by rebasing to the latest develop.

@rpytel1 rpytel1 force-pushed the rudimentary_qTable branch 3 times, most recently from 1d24162 to b550420 Compare January 7, 2019 16:15
@rpytel1
Copy link
Collaborator

rpytel1 commented Jan 7, 2019

I think it all works but would appreciate if someone (@MattSkala) would check it (plebnet check) :)

@rpytel1 rpytel1 force-pushed the rudimentary_qTable branch from 857bbde to 234b7a6 Compare January 9, 2019 11:18
@@ -318,19 +320,17 @@ def select_provider():
"""
if not config.get('chosen_provider'):
logger.log("No provider chosen yet", log_name)
all_providers = dna.vps
all_providers = cloudomate_controller.get_vps_providers().keys()
excluded_providers = config.get('excluded_providers')
available_providers = list(set(all_providers.keys()) - set(excluded_providers))
providers = {k: all_providers[k] for k in all_providers if k in available_providers}

if providers >= 1 and sum(providers.values()) > 0:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the condition should be len(providers) >= 1

@MattSkala
Copy link
Collaborator Author

MattSkala commented Jan 9, 2019

Some notes after a discussion and deeper inspection of the code:

  1. In update_values you should consider the option currently being purchased. If the purchase succeeds, the reward for the particular provider option should be increased, otherwise decreased.
  2. In install_available_servers, a string is passed as a provider parameter to qtable.create_child_qtable, but I think VPSState object is expected. For this, you need to store the option name in cloudomate_controller.purchase_choice to the list of bought services.
  3. In both qtable and environment dictionaries, you are using provider_offer.name as the key. What if more providers are using the same name for their vps options? I think the key should be the combination of both the provider name and option name.
  4. The bandwidth can be unmetered (e.g. see linevast). Currently, it is set to MIN_BANDWIDTH in ProviderOffer.__init_. Instead, I'd replace unmetered bandwidth with an UNLIMITED_BANDWIDTH constant with a reasonable value (10 TB?), so the measure is calculated properly for such offers.
  5. In cloudomate_controller.py in the options function, I would put provider.get_options() call in a try block to protect against cloudomate failures.

@rpytel1
Copy link
Collaborator

rpytel1 commented Jan 9, 2019

Ad 1:
current_state - current offer the program is in
next_state - offer program is trying to purchase
As I recall we were discussing that about one month ago. We decided that if we can't manage to buy chosen offer(next_state) it means that current state(next_state) is not enabling us to replicate. That's why all the entries are updated transitioning to current_state are negatively updated.
What we can do is to mantain what we have and extend it with the significant negative update of the transition: current_state -> next_state

@rpytel1
Copy link
Collaborator

rpytel1 commented Jan 9, 2019

Ad 5: Is it really Pull Request related?

@rpytel1
Copy link
Collaborator

rpytel1 commented Jan 9, 2019

2-4 fixed and tested. I will wait until we decide what to do with 1 and 5 :)

@MattSkala
Copy link
Collaborator Author

Ad 1:

We decided that if we can't manage to buy chosen offer(next_state) it means that current state(next_state) is not enabling us to replicate.

Ok, I think I understand the original motivation now. It probably makes sense for positive updates (we were able to buy the current option, install PlebNet on it, and earn enough BTC).

The negatives update is more complicated though. There are 2 types of failures:

  1. We were not able to earn enough BTC with the current state. In such a case, the condition checking the balance in attempt_purchase would not be evaluated to true in the first place, so no updates occurs anyway. We could probably handle this somehow, but until we have a bot gossip implemented, it does not make much sense to consider this as the bot will die anyway and the table won't be propagated to others.

  2. We were able to earn enough BTC, but the purchase_choice method fails. This means that either the selected provider is broken in cloudomate, or the provider blocks purchases from our IP address. So I think it makes sense to negatively update only the transition from the current state to the chosen offer.

Currently if we fail to purchase a chosen offer, we penalize even the current state for that, which I think is probably not right.

Ad 5: Not really, we can also create a separate issue for that, but I think it's just a two-line change.

@MattSkala
Copy link
Collaborator Author

Also, I had a look at the tests and I think the asserted conditions could be somewhat stronger. Especially in test_update_environment and test_update_values, the test only checks if the values changed. A good test should also check if the values changed correctly.

@MattSkala
Copy link
Collaborator Author

Is 2) really fixed? I can't find any related changes in the last commit. Maybe you forgot to push it.

Ad 4) I think the bandwidth is in TB, so the constant value should be 10 instead of 10000.

@synctext
Copy link
Member

595 additional lines, becoming impressive! Code coverage tracking would be great at some point.

@rpytel1 rpytel1 force-pushed the rudimentary_qTable branch from 2258964 to d716896 Compare January 11, 2019 08:48
@rpytel1
Copy link
Collaborator

rpytel1 commented Jan 11, 2019

AD1: In my opinion it makes sense what you wrote, so I fixed it accordingly.
AD2: You were right, I thought I added it. Changes related are added in the latest commit.
AD4: fixed, my mistake
AD5: ok, fixed
I extended the functionality of tests not to just check if they are not the same but also if they are greater or equal from the before and as well certain value checks are introduced.

Let me know when PR is ready to be merged so I will make everything in one commit with meaningful code message

@rpytel1 rpytel1 force-pushed the rudimentary_qTable branch 2 times, most recently from d8356fa to f3f04d3 Compare January 11, 2019 09:05
@MattSkala
Copy link
Collaborator Author

@rpytel1 Looks good, I think it is ready to merge. We can do any further changes (simulated annealing) as a separate PR. Can you please squash the commits into one?

@rpytel1 rpytel1 force-pushed the rudimentary_qTable branch from f3f04d3 to 7615d8b Compare January 13, 2019 12:29
@MattSkala MattSkala changed the title WIP: Rudimentary q table Rudimentary q table Jan 13, 2019
@MattSkala MattSkala merged commit ebce820 into develop Jan 13, 2019
@MattSkala MattSkala deleted the rudimentary_qTable branch January 21, 2019 10:49
devos50 pushed a commit that referenced this pull request Jul 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants